File indexing completed on 2026-09-20 09:13:13
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef GOOGLE_PROTOBUF_ARENASTRING_H__
0009 #define GOOGLE_PROTOBUF_ARENASTRING_H__
0010
0011 #include <algorithm>
0012 #include <cstdint>
0013 #include <string>
0014 #include <type_traits>
0015 #include <utility>
0016
0017 #include "absl/log/absl_check.h"
0018 #include "absl/strings/string_view.h"
0019 #include "google/protobuf/arena.h"
0020 #include "google/protobuf/explicitly_constructed.h"
0021 #include "google/protobuf/port.h"
0022
0023
0024 #include "google/protobuf/port_def.inc"
0025
0026 #ifdef SWIG
0027 #error "You cannot SWIG proto headers"
0028 #endif
0029
0030
0031 namespace google {
0032 namespace protobuf {
0033 namespace internal {
0034 class EpsCopyInputStream;
0035
0036 class SwapFieldHelper;
0037
0038
0039
0040 class PROTOBUF_EXPORT LazyString {
0041 public:
0042
0043
0044
0045
0046 struct InitValue {
0047 const char* ptr;
0048 size_t size;
0049 };
0050
0051
0052 union {
0053 mutable InitValue init_value_;
0054 alignas(std::string) mutable char string_buf_[sizeof(std::string)];
0055 };
0056 mutable std::atomic<const std::string*> inited_;
0057
0058 const std::string& get() const {
0059
0060 auto* res = inited_.load(std::memory_order_acquire);
0061 if (ABSL_PREDICT_FALSE(res == nullptr)) return Init();
0062 return *res;
0063 }
0064
0065 private:
0066
0067
0068 const std::string& Init() const;
0069 };
0070
0071 class PROTOBUF_EXPORT TaggedStringPtr {
0072 public:
0073
0074
0075 enum Flags {
0076 kArenaBit = 0x1,
0077 kMutableBit = 0x2,
0078 kMask = 0x3
0079 };
0080
0081
0082 enum Type {
0083
0084 kDefault = 0,
0085
0086
0087
0088 kAllocated = kMutableBit,
0089
0090
0091
0092
0093
0094 kMutableArena = kArenaBit | kMutableBit,
0095
0096
0097
0098
0099
0100
0101
0102 kFixedSizeArena = kArenaBit,
0103 };
0104
0105 TaggedStringPtr() = default;
0106 explicit constexpr TaggedStringPtr(const GlobalEmptyString* ptr)
0107 : ptr_(const_cast<void*>(static_cast<const void*>(ptr))) {}
0108
0109
0110
0111 inline const std::string* SetDefault(const std::string* p) {
0112 return TagAs(kDefault, const_cast<std::string*>(p));
0113 }
0114
0115
0116
0117
0118 inline std::string* SetAllocated(std::string* p) {
0119 return TagAs(kAllocated, p);
0120 }
0121
0122
0123
0124
0125 inline std::string* SetFixedSizeArena(std::string* p) {
0126 return TagAs(kFixedSizeArena, p);
0127 }
0128
0129
0130
0131
0132 inline std::string* SetMutableArena(std::string* p) {
0133 return TagAs(kMutableArena, p);
0134 }
0135
0136
0137 inline bool IsMutable() const { return as_int() & kMutableBit; }
0138
0139
0140 inline bool IsDefault() const { return (as_int() & kMask) == kDefault; }
0141
0142
0143
0144 inline std::string* GetIfAllocated() const {
0145 auto allocated = as_int() ^ kAllocated;
0146 if (allocated & kMask) return nullptr;
0147
0148 auto ptr = reinterpret_cast<std::string*>(allocated);
0149 PROTOBUF_ASSUME(ptr != nullptr);
0150 return ptr;
0151 }
0152
0153
0154
0155 inline bool IsArena() const { return as_int() & kArenaBit; }
0156
0157
0158 inline bool IsFixedSizeArena() const {
0159 return (as_int() & kMask) == kFixedSizeArena;
0160 }
0161
0162
0163 inline std::string* Get() const {
0164 return reinterpret_cast<std::string*>(as_int() & ~kMask);
0165 }
0166
0167
0168
0169
0170 inline bool IsNull() const { return ptr_ == nullptr; }
0171
0172
0173
0174 TaggedStringPtr Copy(Arena* arena) const;
0175
0176
0177
0178
0179 TaggedStringPtr Copy(Arena* arena, const LazyString& default_value) const;
0180
0181 private:
0182 static inline void assert_aligned(const void* p) {
0183 static_assert(kMask <= alignof(void*), "Pointer underaligned for bit mask");
0184 static_assert(kMask <= alignof(std::string),
0185 "std::string underaligned for bit mask");
0186 ABSL_DCHECK_EQ(reinterpret_cast<uintptr_t>(p) & kMask, 0UL);
0187 }
0188
0189
0190 TaggedStringPtr ForceCopy(Arena* arena) const;
0191
0192 inline std::string* TagAs(Type type, std::string* p) {
0193 ABSL_DCHECK(p != nullptr);
0194 assert_aligned(p);
0195 ptr_ = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(p) | type);
0196 return p;
0197 }
0198
0199 uintptr_t as_int() const { return reinterpret_cast<uintptr_t>(ptr_); }
0200 void* ptr_;
0201 };
0202
0203 static_assert(std::is_trivial<TaggedStringPtr>::value,
0204 "TaggedStringPtr must be trivial");
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225 struct PROTOBUF_EXPORT ArenaStringPtr {
0226
0227 ArenaStringPtr() = default;
0228
0229
0230 constexpr ArenaStringPtr(const GlobalEmptyString* default_value,
0231 ConstantInitialized)
0232 : tagged_ptr_(default_value) {}
0233
0234
0235
0236
0237 explicit ArenaStringPtr(Arena* arena)
0238 : tagged_ptr_(&fixed_address_empty_string) {
0239 if (DebugHardenForceCopyDefaultString()) {
0240 Set(absl::string_view(""), arena);
0241 }
0242 }
0243
0244
0245
0246
0247
0248 ArenaStringPtr(Arena* arena, const LazyString& default_value)
0249 : tagged_ptr_(&fixed_address_empty_string) {
0250 if (DebugHardenForceCopyDefaultString()) {
0251 Set(absl::string_view(default_value.get()), arena);
0252 }
0253 }
0254
0255
0256
0257
0258
0259
0260
0261 ArenaStringPtr(Arena* arena, const ArenaStringPtr& rhs)
0262 : tagged_ptr_(rhs.tagged_ptr_.Copy(arena)) {}
0263
0264
0265
0266
0267
0268
0269
0270 ArenaStringPtr(Arena* arena, const ArenaStringPtr& rhs,
0271 const LazyString& default_value)
0272 : tagged_ptr_(rhs.tagged_ptr_.Copy(arena, default_value)) {}
0273
0274
0275
0276
0277
0278
0279 inline void InitDefault();
0280
0281
0282
0283
0284 inline void InitExternal(const std::string* str);
0285
0286
0287
0288
0289
0290
0291
0292 inline void InitAllocated(std::string* str, Arena* arena);
0293
0294 void Set(absl::string_view value, Arena* arena);
0295 void Set(std::string&& value, Arena* arena);
0296 template <typename... OverloadDisambiguator>
0297 void Set(const std::string& value, Arena* arena);
0298 void Set(const char* s, Arena* arena);
0299 void Set(const char* s, size_t n, Arena* arena);
0300
0301 void SetBytes(absl::string_view value, Arena* arena);
0302 void SetBytes(std::string&& value, Arena* arena);
0303 template <typename... OverloadDisambiguator>
0304 void SetBytes(const std::string& value, Arena* arena);
0305 void SetBytes(const char* s, Arena* arena);
0306 void SetBytes(const void* p, size_t n, Arena* arena);
0307
0308 template <typename RefWrappedType>
0309 void Set(std::reference_wrapper<RefWrappedType> const_string_ref,
0310 ::google::protobuf::Arena* arena) {
0311 Set(const_string_ref.get(), arena);
0312 }
0313
0314
0315
0316
0317
0318 std::string* Mutable(Arena* arena);
0319 std::string* Mutable(const LazyString& default_value, Arena* arena);
0320
0321
0322
0323
0324
0325
0326
0327
0328 std::string* MutableNoCopy(Arena* arena);
0329
0330
0331 PROTOBUF_NDEBUG_INLINE const std::string& Get() const {
0332
0333 return *tagged_ptr_.Get();
0334 }
0335
0336
0337
0338 PROTOBUF_NDEBUG_INLINE const std::string* UnsafeGetPointer() const
0339 ABSL_ATTRIBUTE_RETURNS_NONNULL {
0340 return tagged_ptr_.Get();
0341 }
0342
0343
0344
0345
0346
0347 [[nodiscard]] std::string* Release();
0348
0349
0350
0351
0352 void SetAllocated(std::string* value, Arena* arena);
0353
0354
0355 void Destroy();
0356
0357
0358
0359
0360
0361 void ClearToEmpty();
0362
0363
0364
0365 void ClearNonDefaultToEmpty();
0366
0367
0368
0369
0370 void ClearToDefault(const LazyString& default_value, ::google::protobuf::Arena* arena);
0371
0372
0373
0374
0375 PROTOBUF_NDEBUG_INLINE static void InternalSwap(ArenaStringPtr* rhs,
0376 ArenaStringPtr* lhs,
0377 Arena* arena);
0378
0379
0380
0381 void UnsafeSetTaggedPointer(TaggedStringPtr value) { tagged_ptr_ = value; }
0382
0383
0384
0385 std::string* UnsafeMutablePointer() ABSL_ATTRIBUTE_RETURNS_NONNULL;
0386
0387
0388 inline bool IsDefault() const { return tagged_ptr_.IsDefault(); }
0389
0390 private:
0391 template <typename... Args>
0392 inline std::string* NewString(Arena* arena, Args&&... args) {
0393 if (arena == nullptr) {
0394 auto* s = new std::string(std::forward<Args>(args)...);
0395 return tagged_ptr_.SetAllocated(s);
0396 } else {
0397 auto* s = Arena::Create<std::string>(arena, std::forward<Args>(args)...);
0398 return tagged_ptr_.SetMutableArena(s);
0399 }
0400 }
0401
0402 TaggedStringPtr tagged_ptr_;
0403
0404 bool IsFixedSizeArena() const { return false; }
0405
0406
0407
0408 PROTOBUF_NDEBUG_INLINE static void UnsafeShallowSwap(ArenaStringPtr* rhs,
0409 ArenaStringPtr* lhs) {
0410 std::swap(lhs->tagged_ptr_, rhs->tagged_ptr_);
0411 }
0412
0413 friend class ::google::protobuf::internal::SwapFieldHelper;
0414 friend class TcParser;
0415
0416
0417
0418
0419
0420 template <typename... Lazy>
0421 std::string* MutableSlow(::google::protobuf::Arena* arena, const Lazy&... lazy_default);
0422
0423 friend class EpsCopyInputStream;
0424 };
0425
0426 inline TaggedStringPtr TaggedStringPtr::Copy(Arena* arena) const {
0427 if (DebugHardenForceCopyDefaultString()) {
0428
0429 return IsNull() ? *this : ForceCopy(arena);
0430 }
0431 return IsDefault() ? *this : ForceCopy(arena);
0432 }
0433
0434 inline TaggedStringPtr TaggedStringPtr::Copy(
0435 Arena* arena, const LazyString& default_value) const {
0436 if (DebugHardenForceCopyDefaultString()) {
0437
0438 TaggedStringPtr hardened(*this);
0439 if (IsDefault()) {
0440 hardened.SetDefault(&default_value.get());
0441 }
0442 return hardened.ForceCopy(arena);
0443 }
0444 return IsDefault() ? *this : ForceCopy(arena);
0445 }
0446
0447 inline void ArenaStringPtr::InitDefault() {
0448 tagged_ptr_ = TaggedStringPtr(&fixed_address_empty_string);
0449 }
0450
0451 inline void ArenaStringPtr::InitExternal(const std::string* str) {
0452 tagged_ptr_.SetDefault(str);
0453 }
0454
0455 inline void ArenaStringPtr::InitAllocated(std::string* str, Arena* arena) {
0456 if (arena != nullptr) {
0457 tagged_ptr_.SetMutableArena(str);
0458 arena->Own(str);
0459 } else {
0460 tagged_ptr_.SetAllocated(str);
0461 }
0462 }
0463
0464 inline void ArenaStringPtr::Set(const char* s, Arena* arena) {
0465 Set(absl::string_view{s}, arena);
0466 }
0467
0468 inline void ArenaStringPtr::Set(const char* s, size_t n, Arena* arena) {
0469 Set(absl::string_view{s, n}, arena);
0470 }
0471
0472 inline void ArenaStringPtr::SetBytes(absl::string_view value, Arena* arena) {
0473 Set(value, arena);
0474 }
0475
0476 template <>
0477 PROTOBUF_EXPORT void ArenaStringPtr::Set(const std::string& value,
0478 Arena* arena);
0479
0480 template <>
0481 inline void ArenaStringPtr::SetBytes(const std::string& value, Arena* arena) {
0482 Set(value, arena);
0483 }
0484
0485 inline void ArenaStringPtr::SetBytes(std::string&& value, Arena* arena) {
0486 Set(std::move(value), arena);
0487 }
0488
0489 inline void ArenaStringPtr::SetBytes(const char* s, Arena* arena) {
0490 Set(s, arena);
0491 }
0492
0493 inline void ArenaStringPtr::SetBytes(const void* p, size_t n, Arena* arena) {
0494 Set(absl::string_view{static_cast<const char*>(p), n}, arena);
0495 }
0496
0497 PROTOBUF_NDEBUG_INLINE void ArenaStringPtr::InternalSwap(ArenaStringPtr* rhs,
0498 ArenaStringPtr* lhs,
0499 Arena* arena) {
0500
0501 (void)arena;
0502 std::swap(lhs->tagged_ptr_, rhs->tagged_ptr_);
0503 if (internal::DebugHardenForceCopyInSwap()) {
0504 for (auto* p : {lhs, rhs}) {
0505 if (p->IsDefault()) continue;
0506 std::string* old_value = p->tagged_ptr_.Get();
0507 std::string* new_value =
0508 p->IsFixedSizeArena()
0509 ? Arena::Create<std::string>(arena, *old_value)
0510 : Arena::Create<std::string>(arena, std::move(*old_value));
0511 if (arena == nullptr) {
0512 delete old_value;
0513 p->tagged_ptr_.SetAllocated(new_value);
0514 } else {
0515 p->tagged_ptr_.SetMutableArena(new_value);
0516 }
0517 }
0518 }
0519 }
0520
0521 inline void ArenaStringPtr::ClearNonDefaultToEmpty() {
0522
0523 ABSL_DCHECK(!tagged_ptr_.IsDefault());
0524 tagged_ptr_.Get()->clear();
0525 }
0526
0527 inline std::string* ArenaStringPtr::UnsafeMutablePointer() {
0528 ABSL_DCHECK(tagged_ptr_.IsMutable());
0529 ABSL_DCHECK(tagged_ptr_.Get() != nullptr);
0530 return tagged_ptr_.Get();
0531 }
0532
0533
0534 }
0535 }
0536 }
0537
0538 #include "google/protobuf/port_undef.inc"
0539
0540 #endif