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// This is the implementation of arena string fields written for the open-source
43// release. The ArenaStringPtr struct below is an internal implementation class
44// and *should not be used* by user code. It is used to collect string
45// operations together into one place and abstract away the underlying
46// string-field pointer representation, so that (for example) an alternate
47// implementation that knew more about ::std::string's internals could integrate more
48// closely with the arena allocator.
49
50namespace google {
51namespace protobuf {
52namespace internal {
53
54template <typename T>
55class TaggedPtr {
56 public:
57 void Set(T* p) { ptr_ = reinterpret_cast<uintptr_t>(p); }
58 T* Get() const { return reinterpret_cast<T*>(ptr_); }
59
60 bool IsNull() { return ptr_ == 0; }
61
62 private:
63 uintptr_t ptr_;
64};
65
66struct LIBPROTOBUF_EXPORT ArenaStringPtr {
67 inline void Set(const ::std::string* default_value,
68 const ::std::string& value, ::google::protobuf::Arena* arena) {
69 if (ptr_ == default_value) {
70 CreateInstance(arena, &value);
71 } else {
72 *ptr_ = value;
73 }
74 }
75
76 inline void SetLite(const ::std::string* default_value,
77 const ::std::string& value,
78 ::google::protobuf::Arena* arena) {
79 Set(default_value, value, arena);
80 }
81
82 // Basic accessors.
83 inline const ::std::string& Get() const { return *ptr_; }
84
85 inline ::std::string* Mutable(const ::std::string* default_value,
86 ::google::protobuf::Arena* arena) {
87 if (ptr_ == default_value) {
88 CreateInstance(arena, default_value);
89 }
90 return ptr_;
91 }
92
93 // Release returns a ::std::string* instance that is heap-allocated and is not
94 // Own()'d by any arena. If the field was not set, it returns NULL. The caller
95 // retains ownership. Clears this field back to NULL state. Used to implement
96 // release_<field>() methods on generated classes.
97 inline ::std::string* Release(const ::std::string* default_value,
98 ::google::protobuf::Arena* arena) {
99 if (ptr_ == default_value) {
100 return NULL;
101 }
102 return ReleaseNonDefault(default_value, arena);
103 }
104
105 // Similar to Release, but ptr_ cannot be the default_value.
106 inline ::std::string* ReleaseNonDefault(
107 const ::std::string* default_value, ::google::protobuf::Arena* arena) {
108 GOOGLE_DCHECK(!IsDefault(default_value));
109 ::std::string* released = NULL;
110 if (arena != NULL) {
111 // ptr_ is owned by the arena.
112 released = new ::std::string;
113 released->swap(*ptr_);
114 } else {
115 released = ptr_;
116 }
117 ptr_ = const_cast< ::std::string* >(default_value);
118 return released;
119 }
120
121 // UnsafeArenaRelease returns a ::std::string*, but it may be arena-owned (i.e.
122 // have its destructor already registered) if arena != NULL. If the field was
123 // not set, this returns NULL. This method clears this field back to NULL
124 // state. Used to implement unsafe_arena_release_<field>() methods on
125 // generated classes.
126 inline ::std::string* UnsafeArenaRelease(const ::std::string* default_value,
127 ::google::protobuf::Arena* /* arena */) {
128 if (ptr_ == default_value) {
129 return NULL;
130 }
131 ::std::string* released = ptr_;
132 ptr_ = const_cast< ::std::string* >(default_value);
133 return released;
134 }
135
136 // Takes a string that is heap-allocated, and takes ownership. The string's
137 // destructor is registered with the arena. Used to implement
138 // set_allocated_<field> in generated classes.
139 inline void SetAllocated(const ::std::string* default_value,
140 ::std::string* value, ::google::protobuf::Arena* arena) {
141 if (arena == NULL && ptr_ != default_value) {
142 Destroy(default_value, arena);
143 }
144 if (value != NULL) {
145 ptr_ = value;
146 if (arena != NULL) {
147 arena->Own(value);
148 }
149 } else {
150 ptr_ = const_cast< ::std::string* >(default_value);
151 }
152 }
153
154 // Takes a string that has lifetime equal to the arena's lifetime. The arena
155 // must be non-null. It is safe only to pass this method a value returned by
156 // UnsafeArenaRelease() on another field of a message in the same arena. Used
157 // to implement unsafe_arena_set_allocated_<field> in generated classes.
158 inline void UnsafeArenaSetAllocated(const ::std::string* default_value,
159 ::std::string* value,
160 ::google::protobuf::Arena* /* arena */) {
161 if (value != NULL) {
162 ptr_ = value;
163 } else {
164 ptr_ = const_cast< ::std::string* >(default_value);
165 }
166 }
167
168 // Swaps internal pointers. Arena-safety semantics: this is guarded by the
169 // logic in Swap()/UnsafeArenaSwap() at the message level, so this method is
170 // 'unsafe' if called directly.
171 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE void Swap(ArenaStringPtr* other) {
172 std::swap(ptr_, other->ptr_);
173 }
174 GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE void Swap(
175 ArenaStringPtr* other, const ::std::string* default_value, Arena* arena) {
176#ifndef NDEBUG
177 // For debug builds, we swap the contents of the string, rather than the
178 // string instances themselves. This invalidates previously taken const
179 // references that are (per our documentation) invalidated by calling Swap()
180 // on the message.
181 //
182 // If both strings are the default_value, swapping is uninteresting.
183 // Otherwise, we use ArenaStringPtr::Mutable() to access the string, to
184 // ensure that we do not try to mutate default_value itself.
185 if (IsDefault(default_value) && other->IsDefault(default_value)) {
186 return;
187 }
188
189 ::std::string* this_ptr = Mutable(default_value, arena);
190 ::std::string* other_ptr = other->Mutable(default_value, arena);
191
192 this_ptr->swap(*other_ptr);
193#else
194 std::swap(ptr_, other->ptr_);
195#endif
196 }
197
198 // Frees storage (if not on an arena).
199 inline void Destroy(const ::std::string* default_value,
200 ::google::protobuf::Arena* arena) {
201 if (arena == NULL && ptr_ != default_value) {
202 delete ptr_;
203 }
204 }
205
206 // Clears content, but keeps allocated string if arena != NULL, to avoid the
207 // overhead of heap operations. After this returns, the content (as seen by
208 // the user) will always be the empty string. Assumes that |default_value|
209 // is an empty string.
210 inline void ClearToEmpty(const ::std::string* default_value,
211 ::google::protobuf::Arena* /* arena */) {
212 if (ptr_ == default_value) {
213 // Already set to default (which is empty) -- do nothing.
214 } else {
215 ptr_->clear();
216 }
217 }
218
219 // Clears content, assuming that the current value is not the empty string
220 // default.
221 inline void ClearNonDefaultToEmpty() {
222 ptr_->clear();
223 }
224 inline void ClearNonDefaultToEmptyNoArena() {
225 ptr_->clear();
226 }
227
228 // Clears content, but keeps allocated string if arena != NULL, to avoid the
229 // overhead of heap operations. After this returns, the content (as seen by
230 // the user) will always be equal to |default_value|.
231 inline void ClearToDefault(const ::std::string* default_value,
232 ::google::protobuf::Arena* /* arena */) {
233 if (ptr_ == default_value) {
234 // Already set to default -- do nothing.
235 } else {
236 // Have another allocated string -- rather than throwing this away and
237 // resetting ptr_ to the canonical default string instance, we just reuse
238 // this instance.
239 *ptr_ = *default_value;
240 }
241 }
242
243 // Called from generated code / reflection runtime only. Resets value to point
244 // to a default string pointer, with the semantics that this ArenaStringPtr
245 // does not own the pointed-to memory. Disregards initial value of ptr_ (so
246 // this is the *ONLY* safe method to call after construction or when
247 // reinitializing after becoming the active field in a oneof union).
248 inline void UnsafeSetDefault(const ::std::string* default_value) {
249 // Casting away 'const' is safe here: accessors ensure that ptr_ is only
250 // returned as a const if it is equal to default_value.
251 ptr_ = const_cast< ::std::string* >(default_value);
252 }
253
254 // The 'NoArena' variants of methods below assume arena == NULL and are
255 // optimized to provide very little overhead relative to a raw string pointer
256 // (while still being in-memory compatible with other code that assumes
257 // ArenaStringPtr). Note the invariant that a class instance that has only
258 // ever been mutated by NoArena methods must *only* be in the String state
259 // (i.e., tag bits are not used), *NEVER* ArenaString. This allows all
260 // tagged-pointer manipulations to be avoided.
261 inline void SetNoArena(const ::std::string* default_value,
262 const ::std::string& value) {
263 if (ptr_ == default_value) {
264 CreateInstanceNoArena(&value);
265 } else {
266 *ptr_ = value;
267 }
268 }
269
270#if LANG_CXX11
271 void SetNoArena(const ::std::string* default_value, ::std::string&& value) {
272 if (IsDefault(default_value)) {
273 ptr_ = new ::std::string(std::move(value));
274 } else {
275 *ptr_ = std::move(value);
276 }
277 }
278#endif
279
280 void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr value);
281
282 inline const ::std::string& GetNoArena() const { return *ptr_; }
283
284 inline ::std::string* MutableNoArena(const ::std::string* default_value) {
285 if (ptr_ == default_value) {
286 CreateInstanceNoArena(default_value);
287 }
288 return ptr_;
289 }
290
291 inline ::std::string* ReleaseNoArena(const ::std::string* default_value) {
292 if (ptr_ == default_value) {
293 return NULL;
294 } else {
295 return ReleaseNonDefaultNoArena(default_value);
296 }
297 }
298
299 inline ::std::string* ReleaseNonDefaultNoArena(
300 const ::std::string* default_value) {
301 GOOGLE_DCHECK(!IsDefault(default_value));
302 ::std::string* released = ptr_;
303 ptr_ = const_cast< ::std::string* >(default_value);
304 return released;
305 }
306
307
308 inline void SetAllocatedNoArena(const ::std::string* default_value,
309 ::std::string* value) {
310 if (ptr_ != default_value) {
311 delete ptr_;
312 }
313 if (value != NULL) {
314 ptr_ = value;
315 } else {
316 ptr_ = const_cast< ::std::string* >(default_value);
317 }
318 }
319
320 inline void DestroyNoArena(const ::std::string* default_value) {
321 if (ptr_ != default_value) {
322 delete ptr_;
323 }
324 }
325
326 inline void ClearToEmptyNoArena(const ::std::string* default_value) {
327 if (ptr_ == default_value) {
328 // Nothing: already equal to default (which is the empty string).
329 } else {
330 ptr_->clear();
331 }
332 }
333
334 inline void ClearToDefaultNoArena(const ::std::string* default_value) {
335 if (ptr_ == default_value) {
336 // Nothing: already set to default.
337 } else {
338 // Reuse existing allocated instance.
339 *ptr_ = *default_value;
340 }
341 }
342
343 // Internal accessor used only at parse time to provide direct access to the
344 // raw pointer from the shared parse routine (in the non-arenas case). The
345 // parse routine does the string allocation in order to save code size in the
346 // generated parsing code.
347 inline ::std::string** UnsafeRawStringPointer() {
348 return &ptr_;
349 }
350
351 inline bool IsDefault(const ::std::string* default_value) const {
352 return ptr_ == default_value;
353 }
354
355 // Internal accessors!!!!
356 void UnsafeSetTaggedPointer(TaggedPtr< ::std::string> value) {
357 ptr_ = value.Get();
358 }
359 // Generated code only! An optimization, in certain cases the generated
360 // code is certain we can obtain a string with no default checks and
361 // tag tests.
362 ::std::string* UnsafeMutablePointer() { return ptr_; }
363
364 private:
365 ::std::string* ptr_;
366
367 GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
368 void CreateInstance(::google::protobuf::Arena* arena,
369 const ::std::string* initial_value) {
370 GOOGLE_DCHECK(initial_value != NULL);
371 // uses "new ::std::string" when arena is nullptr
372 ptr_ = Arena::Create< ::std::string >(arena, *initial_value);
373 }
374 GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
375 void CreateInstanceNoArena(const ::std::string* initial_value) {
376 GOOGLE_DCHECK(initial_value != NULL);
377 ptr_ = new ::std::string(*initial_value);
378 }
379};
380
381} // namespace internal
382} // namespace protobuf
383
384
385
386namespace protobuf {
387namespace internal {
388
389inline void ArenaStringPtr::AssignWithDefault(const ::std::string* default_value,
390 ArenaStringPtr value) {
391 const ::std::string* me = *UnsafeRawStringPointer();
392 const ::std::string* other = *value.UnsafeRawStringPointer();
393 // If the pointers are the same then do nothing.
394 if (me != other) {
395 SetNoArena(default_value, value.GetNoArena());
396 }
397}
398
399} // namespace internal
400} // namespace protobuf
401
402} // namespace google
403#endif // GOOGLE_PROTOBUF_ARENASTRING_H__
404