aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/arenastring.h
blob: 63fd00e567f2bcafd3b3bed87c62dcdb51cb177a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef GOOGLE_PROTOBUF_ARENASTRING_H__
#define GOOGLE_PROTOBUF_ARENASTRING_H__

#include <string>

#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/fastmem.h>
#include <google/protobuf/arena.h>



// This is the implementation of arena string fields written for the open-source
// release. The ArenaStringPtr struct below is an internal implementation class
// and *should not be used* by user code. It is used to collect string
// operations together into one place and abstract away the underlying
// string-field pointer representation, so that (for example) an alternate
// implementation that knew more about ::std::string's internals could integrate more
// closely with the arena allocator.

namespace google {
namespace protobuf {
namespace internal {

struct LIBPROTOBUF_EXPORT ArenaStringPtr {
  inline void Set(const ::std::string* default_value,
                  const ::std::string& value, ::google::protobuf::Arena* arena) {
    if (ptr_ == default_value) {
      CreateInstance(arena, &value);
    } else {
      *ptr_ = value;
    }
  }

  // Basic accessors.
  inline const ::std::string& Get() const { return *ptr_; }

  inline ::std::string* Mutable(const ::std::string* default_value,
                           ::google::protobuf::Arena* arena) {
    if (ptr_ == default_value) {
      CreateInstance(arena, default_value);
    }
    return ptr_;
  }

  // Release returns a ::std::string* instance that is heap-allocated and is not
  // Own()'d by any arena. If the field was not set, it returns NULL. The caller
  // retains ownership. Clears this field back to NULL state. Used to implement
  // release_<field>() methods on generated classes.
  inline ::std::string* Release(const ::std::string* default_value,
                           ::google::protobuf::Arena* arena) {
    if (ptr_ == default_value) {
      return NULL;
    }
    ::std::string* released = NULL;
    if (arena != NULL) {
      // ptr_ is owned by the arena -- we need to return a copy.
      released = new ::std::string(*ptr_);
    } else {
      released = ptr_;
    }
    ptr_ = const_cast< ::std::string* >(default_value);
    return released;
  }

  // UnsafeArenaRelease returns a ::std::string*, but it may be arena-owned (i.e.
  // have its destructor already registered) if arena != NULL. If the field was
  // not set, this returns NULL. This method clears this field back to NULL
  // state. Used to implement unsafe_arena_release_<field>() methods on
  // generated classes.
  inline ::std::string* UnsafeArenaRelease(const ::std::string* default_value,
                                      ::google::protobuf::Arena* /* arena */) {
    if (ptr_ == default_value) {
      return NULL;
    }
    ::std::string* released = ptr_;
    ptr_ = const_cast< ::std::string* >(default_value);
    return released;
  }

  // Takes a string that is heap-allocated, and takes ownership. The string's
  // destructor is registered with the arena. Used to implement
  // set_allocated_<field> in generated classes.
  inline void SetAllocated(const ::std::string* default_value,
                           ::std::string* value, ::google::protobuf::Arena* arena) {
    if (arena == NULL && ptr_ != default_value) {
      Destroy(default_value, arena);
    }
    if (value != NULL) {
      ptr_ = value;
      if (arena != NULL) {
        arena->Own(value);
      }
    } else {
      ptr_ = const_cast< ::std::string* >(default_value);
    }
  }

  // Takes a string that has lifetime equal to the arena's lifetime. The arena
  // must be non-null. It is safe only to pass this method a value returned by
  // UnsafeArenaRelease() on another field of a message in the same arena. Used
  // to implement unsafe_arena_set_allocated_<field> in generated classes.
  inline void UnsafeArenaSetAllocated(const ::std::string* default_value,
                                      ::std::string* value,
                                      ::google::protobuf::Arena* /* arena */) {
    if (value != NULL) {
      ptr_ = value;
    } else {
      ptr_ = const_cast< ::std::string* >(default_value);
    }
  }

  // Swaps internal pointers. Arena-safety semantics: this is guarded by the
  // logic in Swap()/UnsafeArenaSwap() at the message level, so this method is
  // 'unsafe' if called directly.
  GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(ArenaStringPtr* other) {
    std::swap(ptr_, other->ptr_);
  }

  // Frees storage (if not on an arena).
  inline void Destroy(const ::std::string* default_value,
                      ::google::protobuf::Arena* arena) {
    if (arena == NULL && ptr_ != default_value) {
      delete ptr_;
    }
  }

  // Clears content, but keeps allocated string if arena != NULL, to avoid the
  // overhead of heap operations. After this returns, the content (as seen by
  // the user) will always be the empty string. Assumes that |default_value|
  // is an empty string.
  inline void ClearToEmpty(const ::std::string* default_value,
                           ::google::protobuf::Arena* /* arena */) {
    if (ptr_ == default_value) {
      // Already set to default (which is empty) -- do nothing.
    } else {
      ptr_->clear();
    }
  }

  // Clears content, but keeps allocated string if arena != NULL, to avoid the
  // overhead of heap operations. After this returns, the content (as seen by
  // the user) will always be equal to |default_value|.
  inline void ClearToDefault(const ::std::string* default_value,
                             ::google::protobuf::Arena* /* arena */) {
    if (ptr_ == default_value) {
      // Already set to default -- do nothing.
    } else {
      // Have another allocated string -- rather than throwing this away and
      // resetting ptr_ to the canonical default string instance, we just reuse
      // this instance.
      *ptr_ = *default_value;
    }
  }

  // Called from generated code / reflection runtime only. Resets value to point
  // to a default string pointer, with the semantics that this ArenaStringPtr
  // does not own the pointed-to memory. Disregards initial value of ptr_ (so
  // this is the *ONLY* safe method to call after construction or when
  // reinitializing after becoming the active field in a oneof union).
  inline void UnsafeSetDefault(const ::std::string* default_value) {
    // Casting away 'const' is safe here: accessors ensure that ptr_ is only
    // returned as a const if it is equal to default_value.
    ptr_ = const_cast< ::std::string* >(default_value);
  }

  // The 'NoArena' variants of methods below assume arena == NULL and are
  // optimized to provide very little overhead relative to a raw string pointer
  // (while still being in-memory compatible with other code that assumes
  // ArenaStringPtr). Note the invariant that a class instance that has only
  // ever been mutated by NoArena methods must *only* be in the String state
  // (i.e., tag bits are not used), *NEVER* ArenaString. This allows all
  // tagged-pointer manipulations to be avoided.
  inline void SetNoArena(const ::std::string* default_value,
                         const ::std::string& value) {
    if (ptr_ == default_value) {
      CreateInstanceNoArena(&value);
    } else {
      *ptr_ = value;
    }
  }

#if LANG_CXX11
  void SetNoArena(const ::std::string* default_value, ::std::string&& value) {
    if (IsDefault(default_value)) {
      ptr_ = new ::std::string(std::move(value));
    } else {
      *ptr_ = std::move(value);
    }
  }
#endif

  void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr value);

  inline const ::std::string& GetNoArena() const { return *ptr_; }

  inline ::std::string* MutableNoArena(const ::std::string* default_value) {
    if (ptr_ == default_value) {
      CreateInstanceNoArena(default_value);
    }
    return ptr_;
  }

  inline ::std::string* ReleaseNoArena(const ::std::string* default_value) {
    if (ptr_ == default_value) {
      return NULL;
    } else {
      ::std::string* released = ptr_;
      ptr_ = const_cast< ::std::string* >(default_value);
      return released;
    }
  }

  inline void SetAllocatedNoArena(const ::std::string* default_value,
                                  ::std::string* value) {
    if (ptr_ != default_value) {
      delete ptr_;
    }
    if (value != NULL) {
      ptr_ = value;
    } else {
      ptr_ = const_cast< ::std::string* >(default_value);
    }
  }

  inline void DestroyNoArena(const ::std::string* default_value) {
    if (ptr_ != default_value) {
      delete ptr_;
    }
  }

  inline void ClearToEmptyNoArena(const ::std::string* default_value) {
    if (ptr_ == default_value) {
      // Nothing: already equal to default (which is the empty string).
    } else {
      ptr_->clear();
    }
  }

  inline void ClearToDefaultNoArena(const ::std::string* default_value) {
    if (ptr_ == default_value) {
      // Nothing: already set to default.
    } else {
      // Reuse existing allocated instance.
      *ptr_ = *default_value;
    }
  }

  // Internal accessor used only at parse time to provide direct access to the
  // raw pointer from the shared parse routine (in the non-arenas case). The
  // parse routine does the string allocation in order to save code size in the
  // generated parsing code.
  inline ::std::string** UnsafeRawStringPointer() {
    return &ptr_;
  }

  inline bool IsDefault(const ::std::string* default_value) const {
    return ptr_ == default_value;
  }

 private:
  ::std::string* ptr_;

  GOOGLE_ATTRIBUTE_NOINLINE void CreateInstance(::google::protobuf::Arena* arena,
                                         const ::std::string* initial_value) {
    GOOGLE_DCHECK(initial_value != NULL);
    ptr_ = new ::std::string(*initial_value);
    if (arena != NULL) {
      arena->Own(ptr_);
    }
  }
  GOOGLE_ATTRIBUTE_NOINLINE void CreateInstanceNoArena(const ::std::string* initial_value) {
    GOOGLE_DCHECK(initial_value != NULL);
    ptr_ = new ::std::string(*initial_value);
  }
};

}  // namespace internal
}  // namespace protobuf



namespace protobuf {
namespace internal {

inline void ArenaStringPtr::AssignWithDefault(const ::std::string* default_value,
                                       ArenaStringPtr value) {
  const ::std::string* me = *UnsafeRawStringPointer();
  const ::std::string* other = *value.UnsafeRawStringPointer();
  // If the pointers are the same then do nothing.
  if (me != other) {
    SetNoArena(default_value, value.GetNoArena());
  }
}

}  // namespace internal
}  // namespace protobuf

}  // namespace google
#endif  // GOOGLE_PROTOBUF_ARENASTRING_H__