• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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