File indexing completed on 2025-12-16 09:40:59
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
0016 #define ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
0017
0018 #include <atomic>
0019 #include <cassert>
0020 #include <cstddef>
0021 #include <cstdint>
0022 #include <type_traits>
0023
0024 #include "absl/base/attributes.h"
0025 #include "absl/base/config.h"
0026 #include "absl/base/internal/endian.h"
0027 #include "absl/base/internal/invoke.h"
0028 #include "absl/base/optimization.h"
0029 #include "absl/container/internal/compressed_tuple.h"
0030 #include "absl/container/internal/container_memory.h"
0031 #include "absl/meta/type_traits.h"
0032 #include "absl/strings/string_view.h"
0033
0034
0035 #if defined(ABSL_HAVE_CONSTANT_EVALUATED) && \
0036 (defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
0037 defined(ABSL_HAVE_MEMORY_SANITIZER))
0038 #define ABSL_INTERNAL_CORD_HAVE_SANITIZER 1
0039 #endif
0040
0041 #define ABSL_CORD_INTERNAL_NO_SANITIZE \
0042 ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
0043
0044 namespace absl {
0045 ABSL_NAMESPACE_BEGIN
0046 namespace cord_internal {
0047
0048
0049
0050
0051
0052 struct CordRep;
0053 struct CordRepConcat;
0054 struct CordRepExternal;
0055 struct CordRepFlat;
0056 struct CordRepSubstring;
0057 struct CordRepCrc;
0058 class CordRepBtree;
0059
0060 class CordzInfo;
0061
0062
0063 enum CordFeatureDefaults { kCordShallowSubcordsDefault = false };
0064
0065 extern std::atomic<bool> shallow_subcords_enabled;
0066
0067 inline void enable_shallow_subcords(bool enable) {
0068 shallow_subcords_enabled.store(enable, std::memory_order_relaxed);
0069 }
0070
0071 enum Constants {
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081 kInlinedVectorSize = 47,
0082
0083
0084 kMaxBytesToCopy = 511
0085 };
0086
0087
0088 [[noreturn]] void LogFatalNodeType(CordRep* rep);
0089
0090
0091
0092
0093 template <bool nullify_tail = false>
0094 inline void SmallMemmove(char* dst, const char* src, size_t n) {
0095 if (n >= 8) {
0096 assert(n <= 15);
0097 uint64_t buf1;
0098 uint64_t buf2;
0099 memcpy(&buf1, src, 8);
0100 memcpy(&buf2, src + n - 8, 8);
0101 if (nullify_tail) {
0102 memset(dst + 7, 0, 8);
0103 }
0104
0105 #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
0106 #pragma GCC diagnostic push
0107 #pragma GCC diagnostic ignored "-Wstringop-overflow"
0108 #endif
0109 memcpy(dst, &buf1, 8);
0110 memcpy(dst + n - 8, &buf2, 8);
0111 #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
0112 #pragma GCC diagnostic pop
0113 #endif
0114 } else if (n >= 4) {
0115 uint32_t buf1;
0116 uint32_t buf2;
0117 memcpy(&buf1, src, 4);
0118 memcpy(&buf2, src + n - 4, 4);
0119 if (nullify_tail) {
0120 memset(dst + 4, 0, 4);
0121 memset(dst + 7, 0, 8);
0122 }
0123 memcpy(dst, &buf1, 4);
0124 memcpy(dst + n - 4, &buf2, 4);
0125 } else {
0126 if (n != 0) {
0127 dst[0] = src[0];
0128 dst[n / 2] = src[n / 2];
0129 dst[n - 1] = src[n - 1];
0130 }
0131 if (nullify_tail) {
0132 memset(dst + 7, 0, 8);
0133 memset(dst + n, 0, 8);
0134 }
0135 }
0136 }
0137
0138
0139
0140 class RefcountAndFlags {
0141 public:
0142 constexpr RefcountAndFlags() : count_{kRefIncrement} {}
0143 struct Immortal {};
0144 explicit constexpr RefcountAndFlags(Immortal) : count_(kImmortalFlag) {}
0145
0146
0147 inline void Increment() {
0148 count_.fetch_add(kRefIncrement, std::memory_order_relaxed);
0149 }
0150
0151
0152
0153
0154
0155
0156
0157
0158 inline bool Decrement() {
0159 int32_t refcount = count_.load(std::memory_order_acquire);
0160 assert(refcount > 0 || refcount & kImmortalFlag);
0161 return refcount != kRefIncrement &&
0162 count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) !=
0163 kRefIncrement;
0164 }
0165
0166
0167 inline bool DecrementExpectHighRefcount() {
0168 int32_t refcount =
0169 count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel);
0170 assert(refcount > 0 || refcount & kImmortalFlag);
0171 return refcount != kRefIncrement;
0172 }
0173
0174
0175 inline size_t Get() const {
0176 return static_cast<size_t>(count_.load(std::memory_order_acquire) >>
0177 kNumFlags);
0178 }
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188 inline bool IsOne() {
0189 return count_.load(std::memory_order_acquire) == kRefIncrement;
0190 }
0191
0192 bool IsImmortal() const {
0193 return (count_.load(std::memory_order_relaxed) & kImmortalFlag) != 0;
0194 }
0195
0196 private:
0197
0198
0199
0200
0201 enum Flags {
0202 kNumFlags = 1,
0203
0204 kImmortalFlag = 0x1,
0205 kRefIncrement = (1 << kNumFlags),
0206 };
0207
0208 std::atomic<int32_t> count_;
0209 };
0210
0211
0212 enum CordRepKind {
0213 UNUSED_0 = 0,
0214 SUBSTRING = 1,
0215 CRC = 2,
0216 BTREE = 3,
0217 UNUSED_4 = 4,
0218 EXTERNAL = 5,
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229 FLAT = 6,
0230 MAX_FLAT_TAG = 248
0231 };
0232
0233
0234
0235
0236
0237
0238 static_assert(FLAT == EXTERNAL + 1, "EXTERNAL and FLAT not consecutive");
0239
0240 struct CordRep {
0241
0242
0243
0244
0245
0246
0247
0248 struct ExtractResult {
0249 CordRep* tree;
0250 CordRep* extracted;
0251 };
0252
0253 CordRep() = default;
0254 constexpr CordRep(RefcountAndFlags::Immortal immortal, size_t l)
0255 : length(l), refcount(immortal), tag(EXTERNAL), storage{} {}
0256
0257
0258
0259
0260
0261
0262
0263 size_t length;
0264 RefcountAndFlags refcount;
0265
0266
0267 uint8_t tag;
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277 uint8_t storage[3];
0278
0279
0280
0281 constexpr bool IsSubstring() const { return tag == SUBSTRING; }
0282 constexpr bool IsCrc() const { return tag == CRC; }
0283 constexpr bool IsExternal() const { return tag == EXTERNAL; }
0284 constexpr bool IsFlat() const { return tag >= FLAT; }
0285 constexpr bool IsBtree() const { return tag == BTREE; }
0286
0287 inline CordRepSubstring* substring();
0288 inline const CordRepSubstring* substring() const;
0289 inline CordRepCrc* crc();
0290 inline const CordRepCrc* crc() const;
0291 inline CordRepExternal* external();
0292 inline const CordRepExternal* external() const;
0293 inline CordRepFlat* flat();
0294 inline const CordRepFlat* flat() const;
0295 inline CordRepBtree* btree();
0296 inline const CordRepBtree* btree() const;
0297
0298
0299
0300
0301
0302 static void Destroy(CordRep* rep);
0303
0304
0305
0306 static inline CordRep* Ref(CordRep* rep);
0307
0308
0309
0310 static inline void Unref(CordRep* rep);
0311 };
0312
0313 struct CordRepSubstring : public CordRep {
0314 size_t start;
0315 CordRep* child;
0316
0317
0318
0319
0320
0321 static inline CordRepSubstring* Create(CordRep* child, size_t pos, size_t n);
0322
0323
0324
0325
0326
0327
0328
0329 static inline CordRep* Substring(CordRep* rep, size_t pos, size_t n);
0330 };
0331
0332
0333
0334
0335 using ExternalReleaserInvoker = void (*)(CordRepExternal*);
0336
0337
0338
0339 struct CordRepExternal : public CordRep {
0340 CordRepExternal() = default;
0341 explicit constexpr CordRepExternal(absl::string_view str)
0342 : CordRep(RefcountAndFlags::Immortal{}, str.size()),
0343 base(str.data()),
0344 releaser_invoker(nullptr) {}
0345
0346 const char* base;
0347
0348 ExternalReleaserInvoker releaser_invoker;
0349
0350
0351
0352 static void Delete(CordRep* rep);
0353 };
0354
0355
0356 struct Rank0 {};
0357 struct Rank1 : Rank0 {};
0358
0359 template <typename Releaser, typename = ::absl::base_internal::invoke_result_t<
0360 Releaser, absl::string_view>>
0361 void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view data) {
0362 ::absl::base_internal::invoke(std::forward<Releaser>(releaser), data);
0363 }
0364
0365 template <typename Releaser,
0366 typename = ::absl::base_internal::invoke_result_t<Releaser>>
0367 void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view) {
0368 ::absl::base_internal::invoke(std::forward<Releaser>(releaser));
0369 }
0370
0371
0372 template <typename Releaser>
0373 struct CordRepExternalImpl
0374 : public CordRepExternal,
0375 public ::absl::container_internal::CompressedTuple<Releaser> {
0376
0377
0378 template <typename T>
0379 CordRepExternalImpl(T&& releaser, int)
0380 : CordRepExternalImpl::CompressedTuple(std::forward<T>(releaser)) {
0381 this->releaser_invoker = &Release;
0382 }
0383
0384 ~CordRepExternalImpl() {
0385 InvokeReleaser(Rank1{}, std::move(this->template get<0>()),
0386 absl::string_view(base, length));
0387 }
0388
0389 static void Release(CordRepExternal* rep) {
0390 delete static_cast<CordRepExternalImpl*>(rep);
0391 }
0392 };
0393
0394 inline CordRepSubstring* CordRepSubstring::Create(CordRep* child, size_t pos,
0395 size_t n) {
0396 assert(child != nullptr);
0397 assert(n > 0);
0398 assert(n < child->length);
0399 assert(pos < child->length);
0400 assert(n <= child->length - pos);
0401
0402
0403 if (ABSL_PREDICT_FALSE(!(child->IsExternal() || child->IsFlat()))) {
0404 LogFatalNodeType(child);
0405 }
0406
0407 CordRepSubstring* rep = new CordRepSubstring();
0408 rep->length = n;
0409 rep->tag = SUBSTRING;
0410 rep->start = pos;
0411 rep->child = child;
0412 return rep;
0413 }
0414
0415 inline CordRep* CordRepSubstring::Substring(CordRep* rep, size_t pos,
0416 size_t n) {
0417 assert(rep != nullptr);
0418 assert(n != 0);
0419 assert(pos < rep->length);
0420 assert(n <= rep->length - pos);
0421 if (n == rep->length) return CordRep::Ref(rep);
0422 if (rep->IsSubstring()) {
0423 pos += rep->substring()->start;
0424 rep = rep->substring()->child;
0425 }
0426 CordRepSubstring* substr = new CordRepSubstring();
0427 substr->length = n;
0428 substr->tag = SUBSTRING;
0429 substr->start = pos;
0430 substr->child = CordRep::Ref(rep);
0431 return substr;
0432 }
0433
0434 inline void CordRepExternal::Delete(CordRep* rep) {
0435 assert(rep != nullptr && rep->IsExternal());
0436 auto* rep_external = static_cast<CordRepExternal*>(rep);
0437 assert(rep_external->releaser_invoker != nullptr);
0438 rep_external->releaser_invoker(rep_external);
0439 }
0440
0441 template <typename Str>
0442 struct ConstInitExternalStorage {
0443 ABSL_CONST_INIT static CordRepExternal value;
0444 };
0445
0446 template <typename Str>
0447 ABSL_CONST_INIT CordRepExternal
0448 ConstInitExternalStorage<Str>::value(Str::value);
0449
0450 enum {
0451 kMaxInline = 15,
0452 };
0453
0454 constexpr char GetOrNull(absl::string_view data, size_t pos) {
0455 return pos < data.size() ? data[pos] : '\0';
0456 }
0457
0458
0459
0460
0461
0462 using cordz_info_t = int64_t;
0463
0464
0465
0466 static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, "");
0467 static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), "");
0468
0469
0470
0471
0472 static constexpr cordz_info_t LittleEndianByte(unsigned char value) {
0473 #if defined(ABSL_IS_BIG_ENDIAN)
0474 return static_cast<cordz_info_t>(value) << ((sizeof(cordz_info_t) - 1) * 8);
0475 #else
0476 return value;
0477 #endif
0478 }
0479
0480 class InlineData {
0481 public:
0482
0483 enum DefaultInitType { kDefaultInit };
0484
0485
0486
0487
0488
0489 static constexpr cordz_info_t kNullCordzInfo = LittleEndianByte(1);
0490
0491
0492
0493
0494 static constexpr size_t kTagOffset = 0;
0495
0496
0497
0498
0499 #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER
0500 ~InlineData() noexcept { unpoison(); }
0501 #endif
0502
0503 constexpr InlineData() noexcept { poison_this(); }
0504
0505 explicit InlineData(DefaultInitType) noexcept : rep_(kDefaultInit) {
0506 poison_this();
0507 }
0508
0509 explicit InlineData(CordRep* rep) noexcept : rep_(rep) {
0510 ABSL_ASSERT(rep != nullptr);
0511 }
0512
0513
0514
0515
0516 constexpr InlineData(absl::string_view sv, CordRep* rep) noexcept
0517 : rep_(rep ? Rep(rep) : Rep(sv)) {
0518 poison();
0519 }
0520
0521 constexpr InlineData(const InlineData& rhs) noexcept;
0522 InlineData& operator=(const InlineData& rhs) noexcept;
0523 friend void swap(InlineData& lhs, InlineData& rhs) noexcept;
0524
0525 friend bool operator==(const InlineData& lhs, const InlineData& rhs) {
0526 #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER
0527 const Rep l = lhs.rep_.SanitizerSafeCopy();
0528 const Rep r = rhs.rep_.SanitizerSafeCopy();
0529 return memcmp(&l, &r, sizeof(l)) == 0;
0530 #else
0531 return memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
0532 #endif
0533 }
0534 friend bool operator!=(const InlineData& lhs, const InlineData& rhs) {
0535 return !operator==(lhs, rhs);
0536 }
0537
0538
0539
0540 constexpr void poison();
0541
0542
0543 constexpr void unpoison();
0544
0545
0546 constexpr void poison_this();
0547
0548
0549
0550 bool is_empty() const { return rep_.tag() == 0; }
0551
0552
0553 bool is_tree() const { return (rep_.tag() & 1) != 0; }
0554
0555
0556
0557 bool is_profiled() const {
0558 assert(is_tree());
0559 return rep_.cordz_info() != kNullCordzInfo;
0560 }
0561
0562
0563
0564
0565 static bool is_either_profiled(const InlineData& data1,
0566 const InlineData& data2) {
0567 assert(data1.is_tree() && data2.is_tree());
0568 return (data1.rep_.cordz_info() | data2.rep_.cordz_info()) !=
0569 kNullCordzInfo;
0570 }
0571
0572
0573
0574
0575 CordzInfo* cordz_info() const {
0576 assert(is_tree());
0577 intptr_t info = static_cast<intptr_t>(absl::little_endian::ToHost64(
0578 static_cast<uint64_t>(rep_.cordz_info())));
0579 assert(info & 1);
0580 return reinterpret_cast<CordzInfo*>(info - 1);
0581 }
0582
0583
0584
0585
0586 void set_cordz_info(CordzInfo* cordz_info) {
0587 assert(is_tree());
0588 uintptr_t info = reinterpret_cast<uintptr_t>(cordz_info) | 1;
0589 rep_.set_cordz_info(
0590 static_cast<cordz_info_t>(absl::little_endian::FromHost64(info)));
0591 }
0592
0593
0594 void clear_cordz_info() {
0595 assert(is_tree());
0596 rep_.set_cordz_info(kNullCordzInfo);
0597 }
0598
0599
0600
0601 const char* as_chars() const {
0602 assert(!is_tree());
0603 return rep_.as_chars();
0604 }
0605
0606
0607
0608
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621 char* as_chars() { return rep_.as_chars(); }
0622
0623
0624
0625 CordRep* as_tree() const {
0626 assert(is_tree());
0627 return rep_.tree();
0628 }
0629
0630 void set_inline_data(const char* data, size_t n) {
0631 ABSL_ASSERT(n <= kMaxInline);
0632 unpoison();
0633 rep_.set_tag(static_cast<int8_t>(n << 1));
0634 SmallMemmove<true>(rep_.as_chars(), data, n);
0635 poison();
0636 }
0637
0638 void copy_max_inline_to(char* dst) const {
0639 assert(!is_tree());
0640 memcpy(dst, rep_.SanitizerSafeCopy().as_chars(), kMaxInline);
0641 }
0642
0643
0644
0645 void make_tree(CordRep* rep) {
0646 unpoison();
0647 rep_.make_tree(rep);
0648 }
0649
0650
0651
0652
0653 void set_tree(CordRep* rep) {
0654 assert(is_tree());
0655 rep_.set_tree(rep);
0656 }
0657
0658
0659
0660 size_t inline_size() const { return rep_.inline_size(); }
0661
0662
0663
0664
0665 void set_inline_size(size_t size) {
0666 unpoison();
0667 rep_.set_inline_size(size);
0668 poison();
0669 }
0670
0671
0672
0673
0674
0675
0676
0677 int Compare(const InlineData& rhs) const {
0678 return Compare(rep_.SanitizerSafeCopy(), rhs.rep_.SanitizerSafeCopy());
0679 }
0680
0681 private:
0682 struct Rep {
0683
0684 struct AsTree {
0685 explicit constexpr AsTree(absl::cord_internal::CordRep* tree)
0686 : rep(tree) {}
0687 cordz_info_t cordz_info = kNullCordzInfo;
0688 absl::cord_internal::CordRep* rep;
0689 };
0690
0691 explicit Rep(DefaultInitType) {}
0692 constexpr Rep() : data{0} {}
0693 constexpr Rep(const Rep&) = default;
0694 constexpr Rep& operator=(const Rep&) = default;
0695
0696 explicit constexpr Rep(CordRep* rep) : as_tree(rep) {}
0697
0698 explicit constexpr Rep(absl::string_view chars)
0699 : data{static_cast<char>((chars.size() << 1)),
0700 GetOrNull(chars, 0),
0701 GetOrNull(chars, 1),
0702 GetOrNull(chars, 2),
0703 GetOrNull(chars, 3),
0704 GetOrNull(chars, 4),
0705 GetOrNull(chars, 5),
0706 GetOrNull(chars, 6),
0707 GetOrNull(chars, 7),
0708 GetOrNull(chars, 8),
0709 GetOrNull(chars, 9),
0710 GetOrNull(chars, 10),
0711 GetOrNull(chars, 11),
0712 GetOrNull(chars, 12),
0713 GetOrNull(chars, 13),
0714 GetOrNull(chars, 14)} {}
0715
0716
0717 ABSL_CORD_INTERNAL_NO_SANITIZE
0718 int8_t tag() const { return reinterpret_cast<const int8_t*>(this)[0]; }
0719 void set_tag(int8_t rhs) { reinterpret_cast<int8_t*>(this)[0] = rhs; }
0720
0721 char* as_chars() { return data + 1; }
0722 const char* as_chars() const { return data + 1; }
0723
0724 bool is_tree() const { return (tag() & 1) != 0; }
0725
0726 size_t inline_size() const {
0727 ABSL_ASSERT(!is_tree());
0728 return static_cast<size_t>(tag()) >> 1;
0729 }
0730
0731 void set_inline_size(size_t size) {
0732 ABSL_ASSERT(size <= kMaxInline);
0733 set_tag(static_cast<int8_t>(size << 1));
0734 }
0735
0736 CordRep* tree() const { return as_tree.rep; }
0737 void set_tree(CordRep* rhs) { as_tree.rep = rhs; }
0738
0739 cordz_info_t cordz_info() const { return as_tree.cordz_info; }
0740 void set_cordz_info(cordz_info_t rhs) { as_tree.cordz_info = rhs; }
0741
0742 void make_tree(CordRep* tree) {
0743 as_tree.rep = tree;
0744 as_tree.cordz_info = kNullCordzInfo;
0745 }
0746
0747 #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER
0748 constexpr Rep SanitizerSafeCopy() const {
0749 if (!absl::is_constant_evaluated()) {
0750 Rep res;
0751 if (is_tree()) {
0752 res = *this;
0753 } else {
0754 res.set_tag(tag());
0755 memcpy(res.as_chars(), as_chars(), inline_size());
0756 }
0757 return res;
0758 } else {
0759 return *this;
0760 }
0761 }
0762 #else
0763 constexpr const Rep& SanitizerSafeCopy() const { return *this; }
0764 #endif
0765
0766
0767
0768
0769
0770 union {
0771 char data[kMaxInline + 1];
0772 AsTree as_tree;
0773 };
0774
0775
0776 inline void SwapValue(Rep rhs, Rep& refrhs) {
0777 memcpy(&refrhs, this, sizeof(*this));
0778 memcpy(this, &rhs, sizeof(*this));
0779 }
0780 };
0781
0782
0783 static inline int Compare(const Rep& lhs, const Rep& rhs) {
0784 uint64_t x, y;
0785 memcpy(&x, lhs.as_chars(), sizeof(x));
0786 memcpy(&y, rhs.as_chars(), sizeof(y));
0787 if (x == y) {
0788 memcpy(&x, lhs.as_chars() + 7, sizeof(x));
0789 memcpy(&y, rhs.as_chars() + 7, sizeof(y));
0790 if (x == y) {
0791 if (lhs.inline_size() == rhs.inline_size()) return 0;
0792 return lhs.inline_size() < rhs.inline_size() ? -1 : 1;
0793 }
0794 }
0795 x = absl::big_endian::FromHost64(x);
0796 y = absl::big_endian::FromHost64(y);
0797 return x < y ? -1 : 1;
0798 }
0799
0800 Rep rep_;
0801 };
0802
0803 static_assert(sizeof(InlineData) == kMaxInline + 1, "");
0804
0805 #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER
0806
0807 constexpr InlineData::InlineData(const InlineData& rhs) noexcept
0808 : rep_(rhs.rep_.SanitizerSafeCopy()) {
0809 poison();
0810 }
0811
0812 inline InlineData& InlineData::operator=(const InlineData& rhs) noexcept {
0813 unpoison();
0814 rep_ = rhs.rep_.SanitizerSafeCopy();
0815 poison();
0816 return *this;
0817 }
0818
0819 constexpr void InlineData::poison_this() {
0820 if (!absl::is_constant_evaluated()) {
0821 container_internal::SanitizerPoisonObject(this);
0822 }
0823 }
0824
0825 constexpr void InlineData::unpoison() {
0826 if (!absl::is_constant_evaluated()) {
0827 container_internal::SanitizerUnpoisonObject(this);
0828 }
0829 }
0830
0831 constexpr void InlineData::poison() {
0832 if (!absl::is_constant_evaluated()) {
0833 if (is_tree()) {
0834 container_internal::SanitizerUnpoisonObject(this);
0835 } else if (const size_t size = inline_size()) {
0836 if (size < kMaxInline) {
0837 const char* end = rep_.as_chars() + size;
0838 container_internal::SanitizerPoisonMemoryRegion(end, kMaxInline - size);
0839 }
0840 } else {
0841 container_internal::SanitizerPoisonObject(this);
0842 }
0843 }
0844 }
0845
0846 #else
0847
0848 constexpr InlineData::InlineData(const InlineData&) noexcept = default;
0849 inline InlineData& InlineData::operator=(const InlineData&) noexcept = default;
0850
0851 constexpr void InlineData::poison_this() {}
0852 constexpr void InlineData::unpoison() {}
0853 constexpr void InlineData::poison() {}
0854
0855 #endif
0856
0857 inline CordRepSubstring* CordRep::substring() {
0858 assert(IsSubstring());
0859 return static_cast<CordRepSubstring*>(this);
0860 }
0861
0862 inline const CordRepSubstring* CordRep::substring() const {
0863 assert(IsSubstring());
0864 return static_cast<const CordRepSubstring*>(this);
0865 }
0866
0867 inline CordRepExternal* CordRep::external() {
0868 assert(IsExternal());
0869 return static_cast<CordRepExternal*>(this);
0870 }
0871
0872 inline const CordRepExternal* CordRep::external() const {
0873 assert(IsExternal());
0874 return static_cast<const CordRepExternal*>(this);
0875 }
0876
0877 inline CordRep* CordRep::Ref(CordRep* rep) {
0878
0879
0880 ABSL_ASSUME(rep != nullptr);
0881 rep->refcount.Increment();
0882 return rep;
0883 }
0884
0885 inline void CordRep::Unref(CordRep* rep) {
0886 assert(rep != nullptr);
0887
0888
0889 if (ABSL_PREDICT_FALSE(!rep->refcount.DecrementExpectHighRefcount())) {
0890 Destroy(rep);
0891 }
0892 }
0893
0894 inline void swap(InlineData& lhs, InlineData& rhs) noexcept {
0895 lhs.unpoison();
0896 rhs.unpoison();
0897
0898
0899
0900
0901
0902 lhs.rep_.SwapValue(rhs.rep_, rhs.rep_);
0903 rhs.poison();
0904 lhs.poison();
0905 }
0906
0907 }
0908
0909 ABSL_NAMESPACE_END
0910 }
0911 #endif