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/stubs/logging.h> 37 #include <google/protobuf/stubs/common.h> 38 #include <google/protobuf/stubs/fastmem.h> 39 #include <google/protobuf/arena.h> 40 #include <google/protobuf/generated_message_util.h> 41 42 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 struct LIBPROTOBUF_EXPORT ArenaStringPtr { SetArenaStringPtr57 inline void Set(const ::std::string* default_value, 58 const ::std::string& value, ::google::protobuf::Arena* arena) { 59 if (ptr_ == default_value) { 60 CreateInstance(arena, &value); 61 } else { 62 *ptr_ = value; 63 } 64 } 65 66 // Basic accessors. GetArenaStringPtr67 inline const ::std::string& Get(const ::std::string* /* default_value */) const { 68 return *ptr_; 69 } 70 MutableArenaStringPtr71 inline ::std::string* Mutable(const ::std::string* default_value, 72 ::google::protobuf::Arena* arena) { 73 if (ptr_ == default_value) { 74 CreateInstance(arena, default_value); 75 } 76 return ptr_; 77 } 78 79 // Release returns a ::std::string* instance that is heap-allocated and is not 80 // Own()'d by any arena. If the field was not set, it returns NULL. The caller 81 // retains ownership. Clears this field back to NULL state. Used to implement 82 // release_<field>() methods on generated classes. ReleaseArenaStringPtr83 inline ::std::string* Release(const ::std::string* default_value, 84 ::google::protobuf::Arena* arena) { 85 if (ptr_ == default_value) { 86 return NULL; 87 } 88 ::std::string* released = NULL; 89 if (arena != NULL) { 90 // ptr_ is owned by the arena -- we need to return a copy. 91 released = new ::std::string(*ptr_); 92 } else { 93 released = ptr_; 94 } 95 ptr_ = const_cast< ::std::string* >(default_value); 96 return released; 97 } 98 99 // UnsafeArenaRelease returns a ::std::string*, but it may be arena-owned (i.e. 100 // have its destructor already registered) if arena != NULL. If the field was 101 // not set, this returns NULL. This method clears this field back to NULL 102 // state. Used to implement unsafe_arena_release_<field>() methods on 103 // generated classes. UnsafeArenaReleaseArenaStringPtr104 inline ::std::string* UnsafeArenaRelease(const ::std::string* default_value, 105 ::google::protobuf::Arena* /* arena */) { 106 if (ptr_ == default_value) { 107 return NULL; 108 } 109 ::std::string* released = ptr_; 110 ptr_ = const_cast< ::std::string* >(default_value); 111 return released; 112 } 113 114 // Takes a string that is heap-allocated, and takes ownership. The string's 115 // destructor is registered with the arena. Used to implement 116 // set_allocated_<field> in generated classes. SetAllocatedArenaStringPtr117 inline void SetAllocated(const ::std::string* default_value, 118 ::std::string* value, ::google::protobuf::Arena* arena) { 119 if (arena == NULL && ptr_ != default_value) { 120 Destroy(default_value, arena); 121 } 122 if (value != NULL) { 123 ptr_ = value; 124 if (arena != NULL) { 125 arena->Own(value); 126 } 127 } else { 128 ptr_ = const_cast< ::std::string* >(default_value); 129 } 130 } 131 132 // Takes a string that has lifetime equal to the arena's lifetime. The arena 133 // must be non-null. It is safe only to pass this method a value returned by 134 // UnsafeArenaRelease() on another field of a message in the same arena. Used 135 // to implement unsafe_arena_set_allocated_<field> in generated classes. UnsafeArenaSetAllocatedArenaStringPtr136 inline void UnsafeArenaSetAllocated(const ::std::string* default_value, 137 ::std::string* value, 138 ::google::protobuf::Arena* /* arena */) { 139 if (value != NULL) { 140 ptr_ = value; 141 } else { 142 ptr_ = const_cast< ::std::string* >(default_value); 143 } 144 } 145 146 // Swaps internal pointers. Arena-safety semantics: this is guarded by the 147 // logic in Swap()/UnsafeArenaSwap() at the message level, so this method is 148 // 'unsafe' if called directly. SwapArenaStringPtr149 GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(ArenaStringPtr* other) { 150 std::swap(ptr_, other->ptr_); 151 } 152 153 // Frees storage (if not on an arena) and sets field to default value. DestroyArenaStringPtr154 inline void Destroy(const ::std::string* default_value, 155 ::google::protobuf::Arena* arena) { 156 if (arena == NULL && ptr_ != default_value) { 157 delete ptr_; 158 } 159 ptr_ = const_cast< ::std::string* >(default_value); 160 } 161 162 // Clears content, but keeps allocated string if arena != NULL, to avoid the 163 // overhead of heap operations. After this returns, the content (as seen by 164 // the user) will always be the empty string. Assumes that |default_value| 165 // is an empty string. ClearToEmptyArenaStringPtr166 inline void ClearToEmpty(const ::std::string* default_value, 167 ::google::protobuf::Arena* /* arena */) { 168 if (ptr_ == default_value) { 169 // Already set to default (which is empty) -- do nothing. 170 } else { 171 ptr_->clear(); 172 } 173 } 174 175 // Clears content, but keeps allocated string if arena != NULL, to avoid the 176 // overhead of heap operations. After this returns, the content (as seen by 177 // the user) will always be equal to |default_value|. ClearToDefaultArenaStringPtr178 inline void ClearToDefault(const ::std::string* default_value, 179 ::google::protobuf::Arena* /* arena */) { 180 if (ptr_ == default_value) { 181 // Already set to default -- do nothing. 182 } else { 183 // Have another allocated string -- rather than throwing this away and 184 // resetting ptr_ to the canonical default string instance, we just reuse 185 // this instance. 186 *ptr_ = *default_value; 187 } 188 } 189 190 // Called from generated code / reflection runtime only. Resets value to point 191 // to a default string pointer, with the semantics that this ArenaStringPtr 192 // does not own the pointed-to memory. Disregards initial value of ptr_ (so 193 // this is the *ONLY* safe method to call after construction or when 194 // reinitializing after becoming the active field in a oneof union). UnsafeSetDefaultArenaStringPtr195 inline void UnsafeSetDefault(const ::std::string* default_value) { 196 // Casting away 'const' is safe here: accessors ensure that ptr_ is only 197 // returned as a const if it is equal to default_value. 198 ptr_ = const_cast< ::std::string* >(default_value); 199 } 200 201 // The 'NoArena' variants of methods below assume arena == NULL and are 202 // optimized to provide very little overhead relative to a raw string pointer 203 // (while still being in-memory compatible with other code that assumes 204 // ArenaStringPtr). Note the invariant that a class instance that has only 205 // ever been mutated by NoArena methods must *only* be in the String state 206 // (i.e., tag bits are not used), *NEVER* ArenaString. This allows all 207 // tagged-pointer manipulations to be avoided. SetNoArenaArenaStringPtr208 inline void SetNoArena(const ::std::string* default_value, 209 const ::std::string& value) { 210 if (ptr_ == default_value) { 211 CreateInstanceNoArena(&value); 212 } else { 213 *ptr_ = value; 214 } 215 } 216 217 void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr value); 218 GetNoArenaArenaStringPtr219 inline const ::std::string& GetNoArena(const ::std::string* /* default_value */) const { 220 return *ptr_; 221 } 222 MutableNoArenaArenaStringPtr223 inline ::std::string* MutableNoArena(const ::std::string* default_value) { 224 if (ptr_ == default_value) { 225 CreateInstanceNoArena(default_value); 226 } 227 return ptr_; 228 } 229 ReleaseNoArenaArenaStringPtr230 inline ::std::string* ReleaseNoArena(const ::std::string* default_value) { 231 if (ptr_ == default_value) { 232 return NULL; 233 } else { 234 ::std::string* released = ptr_; 235 ptr_ = const_cast< ::std::string* >(default_value); 236 return released; 237 } 238 } 239 SetAllocatedNoArenaArenaStringPtr240 inline void SetAllocatedNoArena(const ::std::string* default_value, 241 ::std::string* value) { 242 if (ptr_ != default_value) { 243 delete ptr_; 244 } 245 if (value != NULL) { 246 ptr_ = value; 247 } else { 248 ptr_ = const_cast< ::std::string* >(default_value); 249 } 250 } 251 DestroyNoArenaArenaStringPtr252 inline void DestroyNoArena(const ::std::string* default_value) { 253 if (ptr_ != default_value) { 254 delete ptr_; 255 } 256 ptr_ = NULL; 257 } 258 ClearToEmptyNoArenaArenaStringPtr259 inline void ClearToEmptyNoArena(const ::std::string* default_value) { 260 if (ptr_ == default_value) { 261 // Nothing: already equal to default (which is the empty string). 262 } else { 263 ptr_->clear(); 264 } 265 } 266 ClearToDefaultNoArenaArenaStringPtr267 inline void ClearToDefaultNoArena(const ::std::string* default_value) { 268 if (ptr_ == default_value) { 269 // Nothing: already set to default. 270 } else { 271 // Reuse existing allocated instance. 272 *ptr_ = *default_value; 273 } 274 } 275 276 // Internal accessor used only at parse time to provide direct access to the 277 // raw pointer from the shared parse routine (in the non-arenas case). The 278 // parse routine does the string allocation in order to save code size in the 279 // generated parsing code. UnsafeRawStringPointerArenaStringPtr280 inline ::std::string** UnsafeRawStringPointer() { 281 return &ptr_; 282 } 283 284 private: 285 ::std::string* ptr_; 286 CreateInstanceArenaStringPtr287 GOOGLE_ATTRIBUTE_NOINLINE void CreateInstance(::google::protobuf::Arena* arena, 288 const ::std::string* initial_value) { 289 // Assumes ptr_ is not NULL. 290 if (initial_value != NULL) { 291 ptr_ = new ::std::string(*initial_value); 292 } else { 293 ptr_ = new ::std::string(); 294 } 295 if (arena != NULL) { 296 arena->Own(ptr_); 297 } 298 } CreateInstanceNoArenaArenaStringPtr299 GOOGLE_ATTRIBUTE_NOINLINE void CreateInstanceNoArena(const ::std::string* initial_value) { 300 if (initial_value != NULL) { 301 ptr_ = new ::std::string(*initial_value); 302 } else { 303 ptr_ = new ::std::string(); 304 } 305 } 306 }; 307 308 } // namespace internal 309 } // namespace protobuf 310 311 312 313 } // namespace google 314 #endif // GOOGLE_PROTOBUF_ARENASTRING_H__ 315