aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/protobuf/src/google/protobuf/inlined_string_field.h
blob: 8fc9d3e69759ecdb645195c637d76e0e4d34de7b (plain) (blame)
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
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
// 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_INLINED_STRING_FIELD_H__
#define GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__

#include <string>
#include <utility>

#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/port.h>
#include <google/protobuf/stubs/strutil.h>

// Must be included last.
#include <google/protobuf/port_def.inc>

#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif

namespace google {
namespace protobuf {

class Arena;

namespace internal {

// InlinedStringField wraps a TProtoStringType instance and exposes an API similar to
// ArenaStringPtr's wrapping of a TProtoStringType* instance.
//
// default_value parameters are taken for consistency with ArenaStringPtr, but
// are not used for most methods. With inlining, these should be removed from
// the generated binary.
//
// InlinedStringField has a donating mechanism that allows string buffer
// allocated on arena. A string is donated means both the string container and
// the data buffer are on arena. The donating mechanism here is similar to the
// one in ArenaStringPtr with some differences:
//
// When an InlinedStringField is constructed, the donating state is true. This
// is because the string container is directly stored in the message on the
// arena:
//
//   Construction: donated=true
//   Arena:
//   +-----------------------+
//   |Message foo:           |
//   | +-------------------+ |
//   | |InlinedStringField:| |
//   | | +-----+           | |
//   | | | | | |           | |
//   | | +-----+           | |
//   | +-------------------+ |
//   +-----------------------+
//
// When lvalue Set is called, the donating state is still true. String data will
// be allocated on the arena:
//
//   Lvalue Set: donated=true
//   Arena:
//   +-----------------------+
//   |Message foo:           |
//   | +-------------------+ |
//   | |InlinedStringField:| |
//   | | +-----+           | |
//   | | | | | |           | |
//   | | +|----+           | |
//   | +--|----------------+ |
//   |    V                  |
//   |  +----------------+   |
//   |  |'f','o','o',... |   |
//   |  +----------------+   |
//   +-----------------------+
//
// Some operations will undonate a donated string, including: Mutable,
// SetAllocated, Rvalue Set, and Swap with a non-donated string.
//
// For more details of the donating states transitions, go/pd-inlined-string.
class PROTOBUF_EXPORT InlinedStringField {
 public:
  InlinedStringField() { Init(); }
  inline void Init() { new (get_mutable()) TProtoStringType(); }
  // Add the dummy parameter just to make InlinedStringField(nullptr)
  // unambiguous.
  constexpr InlinedStringField(
      const ExplicitlyConstructed<TProtoStringType>* /*default_value*/,
      bool /*dummy*/)
      : value_{} {}
  explicit InlinedStringField(const TProtoStringType& default_value);
  explicit InlinedStringField(Arena* arena);
  ~InlinedStringField() { Destruct(); }

  // Lvalue Set. To save space, we pack the donating states of multiple
  // InlinedStringFields into an ui32 `donating_states`. The `mask`
  // indicates the position of the bit for this InlinedStringField. `donated` is
  // whether this field is donated.
  //
  // The caller should guarantee that:
  //
  //   `donated == ((donating_states & ~mask) != 0)`
  //
  // This method never changes the `donating_states`.
  void Set(const TProtoStringType* default_value, ConstStringParam value,
           Arena* arena, bool donated, ui32* /*donating_states*/,
           ui32 /*mask*/) {
    (void)arena;
    (void)donated;
    SetNoArena(default_value, value);
  }

  // Rvalue Set. If this field is donated, this method will undonate this field
  // by mutating the `donating_states` according to `mask`.
  void Set(const TProtoStringType* default_value, TProtoStringType&& value, Arena* arena,
           bool donated, ui32* donating_states, ui32 mask);

  template <typename FirstParam>
  void Set(FirstParam p1, const char* str, ::google::protobuf::Arena* arena, bool donated,
           ui32* donating_states, ui32 mask) {
    Set(p1, ConstStringParam(str), arena, donated, donating_states, mask);
  }

  template <typename FirstParam>
  void Set(FirstParam p1, const char* str, size_t size, ::google::protobuf::Arena* arena,
           bool donated, ui32* donating_states, ui32 mask) {
    ConstStringParam sp{str, size};  // for string_view and `const string &`
    Set(p1, sp, arena, donated, donating_states, mask);
  }

  template <typename FirstParam, typename RefWrappedType>
  void Set(FirstParam p1,
           std::reference_wrapper<RefWrappedType> const_string_ref,
           ::google::protobuf::Arena* arena, bool donated, ui32* donating_states,
           ui32 mask) {
    Set(p1, const_string_ref.get(), arena, donated, donating_states, mask);
  }

  template <typename FirstParam, typename SecondParam>
  void SetBytes(FirstParam p1, SecondParam&& p2, ::google::protobuf::Arena* arena,
                bool donated, ui32* donating_states, ui32 mask) {
    Set(p1, static_cast<SecondParam&&>(p2), arena, donated, donating_states,
        mask);
  }

  template <typename FirstParam>
  void SetBytes(FirstParam p1, const void* str, size_t size,
                ::google::protobuf::Arena* arena, bool donated, ui32* donating_states,
                ui32 mask) {
    // Must work whether ConstStringParam is string_view or `const string &`
    ConstStringParam sp{static_cast<const char*>(str), size};
    Set(p1, sp, arena, donated, donating_states, mask);
  }

  PROTOBUF_NDEBUG_INLINE void SetNoArena(const TProtoStringType* default_value,
                                         StringPiece value);
  PROTOBUF_NDEBUG_INLINE void SetNoArena(const TProtoStringType* default_value,
                                         TProtoStringType&& value);

  // Basic accessors.
  PROTOBUF_NDEBUG_INLINE const TProtoStringType& Get() const { return GetNoArena(); }
  PROTOBUF_NDEBUG_INLINE const TProtoStringType& GetNoArena() const;

  // Mutable returns a TProtoStringType* instance that is heap-allocated. If this
  // field is donated, this method undonates this field by mutating the
  // `donating_states` according to `mask`, and copies the content of the
  // original string to the returning string.
  TProtoStringType* Mutable(const LazyString& default_value, Arena* arena,
                       bool donated, ui32* donating_states, ui32 mask);
  TProtoStringType* Mutable(ArenaStringPtr::EmptyDefault, Arena* arena, bool donated,
                       ui32* donating_states, ui32 mask);

  // Release returns a TProtoStringType* instance that is heap-allocated and is not
  // Own()'d by any arena. If the field is not set, this returns NULL. The
  // caller retains ownership. Clears this field back to NULL state. Used to
  // implement release_<field>() methods on generated classes.
  PROTOBUF_MUST_USE_RESULT TProtoStringType* Release(
      const TProtoStringType* default_value, Arena* arena, bool donated);
  PROTOBUF_MUST_USE_RESULT TProtoStringType* ReleaseNonDefault(
      const TProtoStringType* default_value, Arena* arena);
  TProtoStringType* ReleaseNonDefaultNoArena(const TProtoStringType* default_value);

  // Takes a TProtoStringType that is heap-allocated, and takes ownership. The
  // TProtoStringType's destructor is registered with the arena. Used to implement
  // set_allocated_<field> in generated classes.
  //
  // If this field is donated, this method undonates this field by mutating the
  // `donating_states` according to `mask`.
  void SetAllocated(const TProtoStringType* default_value, TProtoStringType* value,
                    Arena* arena, bool donated, ui32* donating_states,
                    ui32 mask);

  void SetAllocatedNoArena(const TProtoStringType* default_value,
                           TProtoStringType* value);

  // When one of `this` and `from` is donated and the other is not donated, this
  // method will undonate the donated one and swap the two heap-allocated
  // strings.
  PROTOBUF_NDEBUG_INLINE void Swap(InlinedStringField* from,
                                   const TProtoStringType* default_value,
                                   Arena* arena, bool donated,
                                   bool from_donated, ui32* donating_states,
                                   ui32* from_donating_states,
                                   ui32 mask);

  // Frees storage (if not on an arena).
  PROTOBUF_NDEBUG_INLINE void Destroy(const TProtoStringType* default_value,
                                      Arena* arena) {
    if (arena == nullptr) {
      DestroyNoArena(default_value);
    }
  }
  PROTOBUF_NDEBUG_INLINE void DestroyNoArena(const TProtoStringType* default_value);

  // Clears content, but keeps allocated TProtoStringType, to avoid the overhead of
  // heap operations. After this returns, the content (as seen by the user) will
  // always be the empty TProtoStringType.
  PROTOBUF_NDEBUG_INLINE void ClearToEmpty() { ClearNonDefaultToEmpty(); }
  PROTOBUF_NDEBUG_INLINE void ClearNonDefaultToEmpty() {
    get_mutable()->clear();
  }

  // Clears content, but keeps allocated TProtoStringType 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|.
  void ClearToDefault(const LazyString& default_value, Arena* arena,
                      bool donated);

  // Returns a mutable pointer, but doesn't initialize the string to the
  // default value.
  PROTOBUF_NDEBUG_INLINE TProtoStringType* MutableNoArenaNoDefault(
      const TProtoStringType* /*default_value*/);

  // Generated code / reflection only! Returns a mutable pointer to the string.
  PROTOBUF_NDEBUG_INLINE TProtoStringType* UnsafeMutablePointer();

  // InlinedStringField doesn't have things like the `default_value` pointer in
  // ArenaStringPtr.
  bool IsDefault(const TProtoStringType* /*default_value*/) const { return false; }

 private:
  void Destruct() { get_mutable()->~TBasicString(); }

  PROTOBUF_NDEBUG_INLINE TProtoStringType* get_mutable();
  PROTOBUF_NDEBUG_INLINE const TProtoStringType* get_const() const;

  alignas(TProtoStringType) char value_[sizeof(TProtoStringType)];

  TProtoStringType* MutableSlow(::google::protobuf::Arena* arena, bool donated,
                           ui32* donating_states, ui32 mask);


  // When constructed in an Arena, we want our destructor to be skipped.
  friend class ::google::protobuf::Arena;
  typedef void InternalArenaConstructable_;
  typedef void DestructorSkippable_;
};

inline TProtoStringType* InlinedStringField::get_mutable() {
  return reinterpret_cast<TProtoStringType*>(&value_);
}

inline const TProtoStringType* InlinedStringField::get_const() const {
  return reinterpret_cast<const TProtoStringType*>(&value_);
}

inline InlinedStringField::InlinedStringField(
    const TProtoStringType& default_value) {
  new (get_mutable()) TProtoStringType(default_value);
}

inline InlinedStringField::InlinedStringField(Arena* arena) {
  Init();
  if (arena != nullptr) {
    arena->OwnDestructor(get_mutable());
  }
}

inline const TProtoStringType& InlinedStringField::GetNoArena() const {
  return *get_const();
}

inline void InlinedStringField::SetAllocatedNoArena(
    const TProtoStringType* /*default_value*/, TProtoStringType* value) {
  if (value == nullptr) {
    // Currently, inlined string field can't have non empty default.
    get_mutable()->clear();
  } else {
    get_mutable()->assign(std::move(*value));
    delete value;
  }
}

inline void InlinedStringField::DestroyNoArena(const TProtoStringType*) {
  // This is invoked from the generated message's ArenaDtor, which is used to
  // clean up objects not allocated on the Arena.
  this->~InlinedStringField();
}

inline TProtoStringType* InlinedStringField::ReleaseNonDefaultNoArena(
    const TProtoStringType* /*default_value*/) {
  // Currently, inlined string field can't have non empty default.
  auto* released = new TProtoStringType();
  get_mutable()->swap(*released);
  return released;
}

inline void InlinedStringField::SetNoArena(const TProtoStringType* /*default_value*/,
                                           StringPiece value) {
  get_mutable()->assign(value.data(), value.length());
}

inline void InlinedStringField::SetNoArena(const TProtoStringType* /*default_value*/,
                                           TProtoStringType&& value) {
  get_mutable()->assign(std::move(value));
}

inline void InlinedStringField::Swap(
    InlinedStringField* from, const TProtoStringType* /*default_value*/,
    Arena* arena, bool donated, bool from_donated, ui32* donating_states,
    ui32* from_donating_states, ui32 mask) {
#if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
  // If one is donated and the other is not, undonate the donated one.
  if (donated && !from_donated) {
    MutableSlow(arena, donated, donating_states, mask);
  } else if (!donated && from_donated) {
    from->MutableSlow(arena, from_donated, from_donating_states, mask);
  }
  // Then, swap the two undonated strings.
#else
  (void)arena;
  (void)donated;
  (void)from_donated;
  (void)donating_states;
  (void)from_donating_states;
  (void)mask;
#endif
  get_mutable()->swap(*from->get_mutable());
}

inline TProtoStringType* InlinedStringField::MutableNoArenaNoDefault(
    const TProtoStringType*) {
  return get_mutable();
}

inline TProtoStringType* InlinedStringField::UnsafeMutablePointer() {
  return get_mutable();
}

}  // namespace internal
}  // namespace protobuf
}  // namespace google

#include <google/protobuf/port_undef.inc>

#endif  // GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__