1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 #ifndef GOOGLE_PROTOBUF_ARENASTRING_H__
32 #define GOOGLE_PROTOBUF_ARENASTRING_H__
33
34 #include <string>
35
36 #include <google/protobuf/arena.h>
37 #include <google/protobuf/stubs/common.h>
38 #include <google/protobuf/stubs/fastmem.h>
39 #include <google/protobuf/stubs/logging.h>
40 #include <google/protobuf/stubs/port.h>
41
42 #include <google/protobuf/port_def.inc>
43
44 // This is the implementation of arena string fields written for the open-source
45 // release. The ArenaStringPtr struct below is an internal implementation class
46 // and *should not be used* by user code. It is used to collect string
47 // operations together into one place and abstract away the underlying
48 // string-field pointer representation, so that (for example) an alternate
49 // implementation that knew more about ::std::string's internals could integrate more
50 // closely with the arena allocator.
51
52 namespace google {
53 namespace protobuf {
54 namespace internal {
55
56 template <typename T>
57 class TaggedPtr {
58 public:
Set(T * p)59 void Set(T* p) { ptr_ = reinterpret_cast<uintptr_t>(p); }
Get()60 T* Get() const { return reinterpret_cast<T*>(ptr_); }
61
IsNull()62 bool IsNull() { return ptr_ == 0; }
63
64 private:
65 uintptr_t ptr_;
66 };
67
68 struct PROTOBUF_EXPORT ArenaStringPtr {
SetArenaStringPtr69 inline void Set(const ::std::string* default_value,
70 const ::std::string& value, Arena* arena) {
71 if (ptr_ == default_value) {
72 CreateInstance(arena, &value);
73 } else {
74 *ptr_ = value;
75 }
76 }
77
SetLiteArenaStringPtr78 inline void SetLite(const ::std::string* default_value,
79 const ::std::string& value, Arena* arena) {
80 Set(default_value, value, arena);
81 }
82
83 // Basic accessors.
GetArenaStringPtr84 inline const ::std::string& Get() const { return *ptr_; }
85
MutableArenaStringPtr86 inline ::std::string* Mutable(const ::std::string* default_value,
87 Arena* arena) {
88 if (ptr_ == default_value) {
89 CreateInstance(arena, default_value);
90 }
91 return ptr_;
92 }
93
94 // Release returns a ::std::string* instance that is heap-allocated and is not
95 // Own()'d by any arena. If the field was not set, it returns NULL. The caller
96 // retains ownership. Clears this field back to NULL state. Used to implement
97 // release_<field>() methods on generated classes.
ReleaseArenaStringPtr98 inline ::std::string* Release(const ::std::string* default_value,
99 Arena* arena) {
100 if (ptr_ == default_value) {
101 return NULL;
102 }
103 return ReleaseNonDefault(default_value, arena);
104 }
105
106 // Similar to Release, but ptr_ cannot be the default_value.
ReleaseNonDefaultArenaStringPtr107 inline ::std::string* ReleaseNonDefault(const ::std::string* default_value,
108 Arena* arena) {
109 GOOGLE_DCHECK(!IsDefault(default_value));
110 ::std::string* released = NULL;
111 if (arena != NULL) {
112 // ptr_ is owned by the arena.
113 released = new ::std::string;
114 released->swap(*ptr_);
115 } else {
116 released = ptr_;
117 }
118 ptr_ = const_cast< ::std::string* >(default_value);
119 return released;
120 }
121
122 // UnsafeArenaRelease returns a ::std::string*, but it may be arena-owned (i.e.
123 // have its destructor already registered) if arena != NULL. If the field was
124 // not set, this returns NULL. This method clears this field back to NULL
125 // state. Used to implement unsafe_arena_release_<field>() methods on
126 // generated classes.
UnsafeArenaReleaseArenaStringPtr127 inline ::std::string* UnsafeArenaRelease(const ::std::string* default_value,
128 Arena* /* arena */) {
129 if (ptr_ == default_value) {
130 return NULL;
131 }
132 ::std::string* released = ptr_;
133 ptr_ = const_cast< ::std::string* >(default_value);
134 return released;
135 }
136
137 // Takes a string that is heap-allocated, and takes ownership. The string's
138 // destructor is registered with the arena. Used to implement
139 // set_allocated_<field> in generated classes.
SetAllocatedArenaStringPtr140 inline void SetAllocated(const ::std::string* default_value,
141 ::std::string* value, Arena* arena) {
142 if (arena == NULL && ptr_ != default_value) {
143 Destroy(default_value, arena);
144 }
145 if (value != NULL) {
146 ptr_ = value;
147 if (arena != NULL) {
148 arena->Own(value);
149 }
150 } else {
151 ptr_ = const_cast< ::std::string* >(default_value);
152 }
153 }
154
155 // Takes a string that has lifetime equal to the arena's lifetime. The arena
156 // must be non-null. It is safe only to pass this method a value returned by
157 // UnsafeArenaRelease() on another field of a message in the same arena. Used
158 // to implement unsafe_arena_set_allocated_<field> in generated classes.
UnsafeArenaSetAllocatedArenaStringPtr159 inline void UnsafeArenaSetAllocated(const ::std::string* default_value,
160 ::std::string* value,
161 Arena* /* arena */) {
162 if (value != NULL) {
163 ptr_ = value;
164 } else {
165 ptr_ = const_cast< ::std::string* >(default_value);
166 }
167 }
168
169 // Swaps internal pointers. Arena-safety semantics: this is guarded by the
170 // logic in Swap()/UnsafeArenaSwap() at the message level, so this method is
171 // 'unsafe' if called directly.
SwapArenaStringPtr172 PROTOBUF_ALWAYS_INLINE void Swap(ArenaStringPtr* other) {
173 std::swap(ptr_, other->ptr_);
174 }
SwapArenaStringPtr175 PROTOBUF_ALWAYS_INLINE void Swap(ArenaStringPtr* other,
176 const ::std::string* default_value,
177 Arena* arena) {
178 #ifndef NDEBUG
179 // For debug builds, we swap the contents of the string, rather than the
180 // string instances themselves. This invalidates previously taken const
181 // references that are (per our documentation) invalidated by calling Swap()
182 // on the message.
183 //
184 // If both strings are the default_value, swapping is uninteresting.
185 // Otherwise, we use ArenaStringPtr::Mutable() to access the string, to
186 // ensure that we do not try to mutate default_value itself.
187 if (IsDefault(default_value) && other->IsDefault(default_value)) {
188 return;
189 }
190
191 ::std::string* this_ptr = Mutable(default_value, arena);
192 ::std::string* other_ptr = other->Mutable(default_value, arena);
193
194 this_ptr->swap(*other_ptr);
195 #else
196 std::swap(ptr_, other->ptr_);
197 (void)default_value;
198 (void)arena;
199 #endif
200 }
201
202 // Frees storage (if not on an arena).
DestroyArenaStringPtr203 inline void Destroy(const ::std::string* default_value, Arena* arena) {
204 if (arena == NULL && ptr_ != default_value) {
205 delete ptr_;
206 }
207 }
208
209 // Clears content, but keeps allocated string if arena != NULL, to avoid the
210 // overhead of heap operations. After this returns, the content (as seen by
211 // the user) will always be the empty string. Assumes that |default_value|
212 // is an empty string.
ClearToEmptyArenaStringPtr213 inline void ClearToEmpty(const ::std::string* default_value,
214 Arena* /* arena */) {
215 if (ptr_ == default_value) {
216 // Already set to default (which is empty) -- do nothing.
217 } else {
218 ptr_->clear();
219 }
220 }
221
222 // Clears content, assuming that the current value is not the empty string
223 // default.
ClearNonDefaultToEmptyArenaStringPtr224 inline void ClearNonDefaultToEmpty() {
225 ptr_->clear();
226 }
ClearNonDefaultToEmptyNoArenaArenaStringPtr227 inline void ClearNonDefaultToEmptyNoArena() {
228 ptr_->clear();
229 }
230
231 // Clears content, but keeps allocated string if arena != NULL, to avoid the
232 // overhead of heap operations. After this returns, the content (as seen by
233 // the user) will always be equal to |default_value|.
ClearToDefaultArenaStringPtr234 inline void ClearToDefault(const ::std::string* default_value,
235 Arena* /* arena */) {
236 if (ptr_ == default_value) {
237 // Already set to default -- do nothing.
238 } else {
239 // Have another allocated string -- rather than throwing this away and
240 // resetting ptr_ to the canonical default string instance, we just reuse
241 // this instance.
242 *ptr_ = *default_value;
243 }
244 }
245
246 // Called from generated code / reflection runtime only. Resets value to point
247 // to a default string pointer, with the semantics that this ArenaStringPtr
248 // does not own the pointed-to memory. Disregards initial value of ptr_ (so
249 // this is the *ONLY* safe method to call after construction or when
250 // reinitializing after becoming the active field in a oneof union).
UnsafeSetDefaultArenaStringPtr251 inline void UnsafeSetDefault(const ::std::string* default_value) {
252 // Casting away 'const' is safe here: accessors ensure that ptr_ is only
253 // returned as a const if it is equal to default_value.
254 ptr_ = const_cast< ::std::string* >(default_value);
255 }
256
257 // The 'NoArena' variants of methods below assume arena == NULL and are
258 // optimized to provide very little overhead relative to a raw string pointer
259 // (while still being in-memory compatible with other code that assumes
260 // ArenaStringPtr). Note the invariant that a class instance that has only
261 // ever been mutated by NoArena methods must *only* be in the String state
262 // (i.e., tag bits are not used), *NEVER* ArenaString. This allows all
263 // tagged-pointer manipulations to be avoided.
SetNoArenaArenaStringPtr264 inline void SetNoArena(const ::std::string* default_value,
265 const ::std::string& value) {
266 if (ptr_ == default_value) {
267 CreateInstanceNoArena(&value);
268 } else {
269 *ptr_ = value;
270 }
271 }
272
273 #if LANG_CXX11
SetNoArenaArenaStringPtr274 void SetNoArena(const ::std::string* default_value, ::std::string&& value) {
275 if (IsDefault(default_value)) {
276 ptr_ = new ::std::string(std::move(value));
277 } else {
278 *ptr_ = std::move(value);
279 }
280 }
281 #endif
282
283 void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr value);
284
GetNoArenaArenaStringPtr285 inline const ::std::string& GetNoArena() const { return *ptr_; }
286
MutableNoArenaArenaStringPtr287 inline ::std::string* MutableNoArena(const ::std::string* default_value) {
288 if (ptr_ == default_value) {
289 CreateInstanceNoArena(default_value);
290 }
291 return ptr_;
292 }
293
ReleaseNoArenaArenaStringPtr294 inline ::std::string* ReleaseNoArena(const ::std::string* default_value) {
295 if (ptr_ == default_value) {
296 return NULL;
297 } else {
298 return ReleaseNonDefaultNoArena(default_value);
299 }
300 }
301
ReleaseNonDefaultNoArenaArenaStringPtr302 inline ::std::string* ReleaseNonDefaultNoArena(
303 const ::std::string* default_value) {
304 GOOGLE_DCHECK(!IsDefault(default_value));
305 ::std::string* released = ptr_;
306 ptr_ = const_cast< ::std::string* >(default_value);
307 return released;
308 }
309
310
SetAllocatedNoArenaArenaStringPtr311 inline void SetAllocatedNoArena(const ::std::string* default_value,
312 ::std::string* value) {
313 if (ptr_ != default_value) {
314 delete ptr_;
315 }
316 if (value != NULL) {
317 ptr_ = value;
318 } else {
319 ptr_ = const_cast< ::std::string* >(default_value);
320 }
321 }
322
DestroyNoArenaArenaStringPtr323 inline void DestroyNoArena(const ::std::string* default_value) {
324 if (ptr_ != default_value) {
325 delete ptr_;
326 }
327 }
328
ClearToEmptyNoArenaArenaStringPtr329 inline void ClearToEmptyNoArena(const ::std::string* default_value) {
330 if (ptr_ == default_value) {
331 // Nothing: already equal to default (which is the empty string).
332 } else {
333 ptr_->clear();
334 }
335 }
336
ClearToDefaultNoArenaArenaStringPtr337 inline void ClearToDefaultNoArena(const ::std::string* default_value) {
338 if (ptr_ == default_value) {
339 // Nothing: already set to default.
340 } else {
341 // Reuse existing allocated instance.
342 *ptr_ = *default_value;
343 }
344 }
345
346 // Internal accessor used only at parse time to provide direct access to the
347 // raw pointer from the shared parse routine (in the non-arenas case). The
348 // parse routine does the string allocation in order to save code size in the
349 // generated parsing code.
UnsafeRawStringPointerArenaStringPtr350 inline ::std::string** UnsafeRawStringPointer() {
351 return &ptr_;
352 }
353
IsDefaultArenaStringPtr354 inline bool IsDefault(const ::std::string* default_value) const {
355 return ptr_ == default_value;
356 }
357
358 // Internal accessors!!!!
UnsafeSetTaggedPointerArenaStringPtr359 void UnsafeSetTaggedPointer(TaggedPtr< ::std::string> value) {
360 ptr_ = value.Get();
361 }
362 // Generated code only! An optimization, in certain cases the generated
363 // code is certain we can obtain a string with no default checks and
364 // tag tests.
UnsafeMutablePointerArenaStringPtr365 ::std::string* UnsafeMutablePointer() { return ptr_; }
366
367 private:
368 ::std::string* ptr_;
369
370 PROTOBUF_NOINLINE
CreateInstanceArenaStringPtr371 void CreateInstance(Arena* arena, const ::std::string* initial_value) {
372 GOOGLE_DCHECK(initial_value != NULL);
373 // uses "new ::std::string" when arena is nullptr
374 ptr_ = Arena::Create< ::std::string >(arena, *initial_value);
375 }
376 PROTOBUF_NOINLINE
CreateInstanceNoArenaArenaStringPtr377 void CreateInstanceNoArena(const ::std::string* initial_value) {
378 GOOGLE_DCHECK(initial_value != NULL);
379 ptr_ = new ::std::string(*initial_value);
380 }
381 };
382
383 } // namespace internal
384 } // namespace protobuf
385
386
387
388 namespace protobuf {
389 namespace internal {
390
AssignWithDefault(const::std::string * default_value,ArenaStringPtr value)391 inline void ArenaStringPtr::AssignWithDefault(const ::std::string* default_value,
392 ArenaStringPtr value) {
393 const ::std::string* me = *UnsafeRawStringPointer();
394 const ::std::string* other = *value.UnsafeRawStringPointer();
395 // If the pointers are the same then do nothing.
396 if (me != other) {
397 SetNoArena(default_value, value.GetNoArena());
398 }
399 }
400
401 } // namespace internal
402 } // namespace protobuf
403 } // namespace google
404
405 #include <google/protobuf/port_undef.inc>
406
407 #endif // GOOGLE_PROTOBUF_ARENASTRING_H__
408