Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:40:59

0001 // Copyright 2021 The Abseil Authors.
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //      https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
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 // We can only add poisoning if we can detect consteval executions.
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 // The overhead of a vtable is too much for Cord, so we roll our own subclasses
0049 // using only a single byte to differentiate classes from each other - the "tag"
0050 // byte.  Define the subclasses first so we can provide downcasting helper
0051 // functions in the base class.
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 // Default feature enable states for cord ring buffers
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   // The inlined size to use with absl::InlinedVector.
0073   //
0074   // Note: The InlinedVectors in this file (and in cord.h) do not need to use
0075   // the same value for their inlined size. The fact that they do is historical.
0076   // It may be desirable for each to use a different inlined size optimized for
0077   // that InlinedVector's usage.
0078   //
0079   // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
0080   // the inlined vector size (47 exists for backward compatibility).
0081   kInlinedVectorSize = 47,
0082 
0083   // Prefer copying blocks of at most this size, otherwise reference count.
0084   kMaxBytesToCopy = 511
0085 };
0086 
0087 // Emits a fatal error "Unexpected node type: xyz" and aborts the program.
0088 [[noreturn]] void LogFatalNodeType(CordRep* rep);
0089 
0090 // Fast implementation of memmove for up to 15 bytes. This implementation is
0091 // safe for overlapping regions. If nullify_tail is true, the destination is
0092 // padded with '\0' up to 15 bytes.
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     // GCC 12 has a false-positive -Wstringop-overflow warning here.
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 // Compact class for tracking the reference count and state flags for CordRep
0139 // instances.  Data is stored in an atomic int32_t for compactness and speed.
0140 class RefcountAndFlags {
0141  public:
0142   constexpr RefcountAndFlags() : count_{kRefIncrement} {}
0143   struct Immortal {};
0144   explicit constexpr RefcountAndFlags(Immortal) : count_(kImmortalFlag) {}
0145 
0146   // Increments the reference count. Imposes no memory ordering.
0147   inline void Increment() {
0148     count_.fetch_add(kRefIncrement, std::memory_order_relaxed);
0149   }
0150 
0151   // Asserts that the current refcount is greater than 0. If the refcount is
0152   // greater than 1, decrements the reference count.
0153   //
0154   // Returns false if there are no references outstanding; true otherwise.
0155   // Inserts barriers to ensure that state written before this method returns
0156   // false will be visible to a thread that just observed this method returning
0157   // false.  Always returns false when the immortal bit is set.
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   // Same as Decrement but expect that refcount is greater than 1.
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   // Returns the current reference count using acquire semantics.
0175   inline size_t Get() const {
0176     return static_cast<size_t>(count_.load(std::memory_order_acquire) >>
0177                                kNumFlags);
0178   }
0179 
0180   // Returns whether the atomic integer is 1.
0181   // If the reference count is used in the conventional way, a
0182   // reference count of 1 implies that the current thread owns the
0183   // reference and no other thread shares it.
0184   // This call performs the test for a reference count of one, and
0185   // performs the memory barrier needed for the owning thread
0186   // to act on the object, knowing that it has exclusive access to the
0187   // object. Always returns false when the immortal bit is set.
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   // We reserve the bottom bit for flag.
0198   // kImmortalBit indicates that this entity should never be collected; it is
0199   // used for the StringConstant constructor to avoid collecting immutable
0200   // constant cords.
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 // Various representations that we allow
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   // We have different tags for different sized flat arrays,
0221   // starting with FLAT, and limited to MAX_FLAT_TAG. The below values map to an
0222   // allocated range of 32 bytes to 256 KB. The current granularity is:
0223   // - 8 byte granularity for flat sizes in [32 - 512]
0224   // - 64 byte granularity for flat sizes in (512 - 8KiB]
0225   // - 4KiB byte granularity for flat sizes in (8KiB, 256 KiB]
0226   // If a new tag is needed in the future, then 'FLAT' and 'MAX_FLAT_TAG' should
0227   // be adjusted as well as the Tag <---> Size mapping logic so that FLAT still
0228   // represents the minimum flat allocation size. (32 bytes as of now).
0229   FLAT = 6,
0230   MAX_FLAT_TAG = 248
0231 };
0232 
0233 // There are various locations where we want to check if some rep is a 'plain'
0234 // data edge, i.e. an external or flat rep. By having FLAT == EXTERNAL + 1, we
0235 // can perform this check in a single branch as 'tag >= EXTERNAL'
0236 // Note that we can leave this optimization to the compiler. The compiler will
0237 // DTRT when it sees a condition like `tag == EXTERNAL || tag >= FLAT`.
0238 static_assert(FLAT == EXTERNAL + 1, "EXTERNAL and FLAT not consecutive");
0239 
0240 struct CordRep {
0241   // Result from an `extract edge` operation. Contains the (possibly changed)
0242   // tree node as well as the extracted edge, or {tree, nullptr} if no edge
0243   // could be extracted.
0244   // On success, the returned `tree` value is null if `extracted` was the only
0245   // data edge inside the tree, a data edge if there were only two data edges in
0246   // the tree, or the (possibly new / smaller) remaining tree with the extracted
0247   // data edge removed.
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   // The following three fields have to be less than 32 bytes since
0258   // that is the smallest supported flat node size. Some code optimizations rely
0259   // on the specific layout of these fields. Notably: the non-trivial field
0260   // `refcount` being preceded by `length`, and being tailed by POD data
0261   // members only.
0262   // LINT.IfChange
0263   size_t length;
0264   RefcountAndFlags refcount;
0265   // If tag < FLAT, it represents CordRepKind and indicates the type of node.
0266   // Otherwise, the node type is CordRepFlat and the tag is the encoded size.
0267   uint8_t tag;
0268 
0269   // `storage` provides two main purposes:
0270   // - the starting point for FlatCordRep.Data() [flexible-array-member]
0271   // - 3 bytes of additional storage for use by derived classes.
0272   // The latter is used by CordrepConcat and CordRepBtree. CordRepConcat stores
0273   // a 'depth' value in storage[0], and the (future) CordRepBtree class stores
0274   // `height`, `begin` and `end` in the 3 entries. Otherwise we would need to
0275   // allocate room for these in the derived class, as not all compilers reuse
0276   // padding space from the base class (clang and gcc do, MSVC does not, etc)
0277   uint8_t storage[3];
0278   // LINT.ThenChange(cord_rep_btree.h:copy_raw)
0279 
0280   // Returns true if this instance's tag matches the requested type.
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   // Memory management
0300 
0301   // Destroys the provided `rep`.
0302   static void Destroy(CordRep* rep);
0303 
0304   // Increments the reference count of `rep`.
0305   // Requires `rep` to be a non-null pointer value.
0306   static inline CordRep* Ref(CordRep* rep);
0307 
0308   // Decrements the reference count of `rep`. Destroys rep if count reaches
0309   // zero. Requires `rep` to be a non-null pointer value.
0310   static inline void Unref(CordRep* rep);
0311 };
0312 
0313 struct CordRepSubstring : public CordRep {
0314   size_t start;  // Starting offset of substring in child
0315   CordRep* child;
0316 
0317   // Creates a substring on `child`, adopting a reference on `child`.
0318   // Requires `child` to be either a flat or external node, and `pos` and `n` to
0319   // form a non-empty partial sub range of `'child`, i.e.:
0320   // `n > 0 && n < length && n + pos <= length`
0321   static inline CordRepSubstring* Create(CordRep* child, size_t pos, size_t n);
0322 
0323   // Creates a substring of `rep`. Does not adopt a reference on `rep`.
0324   // Requires `IsDataEdge(rep) && n > 0 && pos + n <= rep->length`.
0325   // If `n == rep->length` then this method returns `CordRep::Ref(rep)`
0326   // If `rep` is a substring of a flat or external node, then this method will
0327   // return a new substring of that flat or external node with `pos` adjusted
0328   // with the original `start` position.
0329   static inline CordRep* Substring(CordRep* rep, size_t pos, size_t n);
0330 };
0331 
0332 // Type for function pointer that will invoke the releaser function and also
0333 // delete the `CordRepExternalImpl` corresponding to the passed in
0334 // `CordRepExternal`.
0335 using ExternalReleaserInvoker = void (*)(CordRepExternal*);
0336 
0337 // External CordReps are allocated together with a type erased releaser. The
0338 // releaser is stored in the memory directly following the CordRepExternal.
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   // Pointer to function that knows how to call and destroy the releaser.
0348   ExternalReleaserInvoker releaser_invoker;
0349 
0350   // Deletes (releases) the external rep.
0351   // Requires rep != nullptr and rep->IsExternal()
0352   static void Delete(CordRep* rep);
0353 };
0354 
0355 // Use go/ranked-overloads for dispatching.
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 // We use CompressedTuple so that we can benefit from EBCO.
0372 template <typename Releaser>
0373 struct CordRepExternalImpl
0374     : public CordRepExternal,
0375       public ::absl::container_internal::CompressedTuple<Releaser> {
0376   // The extra int arg is so that we can avoid interfering with copy/move
0377   // constructors while still benefitting from perfect forwarding.
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   // Move to strategical places inside the Cord logic and make this an assert.
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 // We store cordz_info as 64 bit pointer value in little endian format. This
0459 // guarantees that the least significant byte of cordz_info matches the first
0460 // byte of the inline data representation in `data`, which holds the inlined
0461 // size or the 'is_tree' bit.
0462 using cordz_info_t = int64_t;
0463 
0464 // Assert that the `cordz_info` pointer value perfectly overlaps the last half
0465 // of `data` and can hold a pointer value.
0466 static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, "");
0467 static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), "");
0468 
0469 // LittleEndianByte() creates a little endian representation of 'value', i.e.:
0470 // a little endian value where the first byte in the host's representation
0471 // holds 'value`, with all other bytes being 0.
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   // DefaultInitType forces the use of the default initialization constructor.
0483   enum DefaultInitType { kDefaultInit };
0484 
0485   // kNullCordzInfo holds the little endian representation of intptr_t(1)
0486   // This is the 'null' / initial value of 'cordz_info'. The null value
0487   // is specifically big endian 1 as with 64-bit pointers, the last
0488   // byte of cordz_info overlaps with the last byte holding the tag.
0489   static constexpr cordz_info_t kNullCordzInfo = LittleEndianByte(1);
0490 
0491   // kTagOffset contains the offset of the control byte / tag. This constant is
0492   // intended mostly for debugging purposes: do not remove this constant as it
0493   // is actively inspected and used by gdb pretty printing code.
0494   static constexpr size_t kTagOffset = 0;
0495 
0496   // Implement `~InlineData()` conditionally: we only need this destructor to
0497   // unpoison poisoned instances under *SAN, and it will only compile correctly
0498   // if the current compiler supports `absl::is_constant_evaluated()`.
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   // Explicit constexpr constructor to create a constexpr InlineData
0514   // value. Creates an inlined SSO value if `rep` is null, otherwise
0515   // creates a tree instance value.
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   // Poisons the unused inlined SSO data if the current instance
0539   // is inlined, else un-poisons the entire instance.
0540   constexpr void poison();
0541 
0542   // Un-poisons this instance.
0543   constexpr void unpoison();
0544 
0545   // Poisons the current instance. This is used on default initialization.
0546   constexpr void poison_this();
0547 
0548   // Returns true if the current instance is empty.
0549   // The 'empty value' is an inlined data value of zero length.
0550   bool is_empty() const { return rep_.tag() == 0; }
0551 
0552   // Returns true if the current instance holds a tree value.
0553   bool is_tree() const { return (rep_.tag() & 1) != 0; }
0554 
0555   // Returns true if the current instance holds a cordz_info value.
0556   // Requires the current instance to hold a tree value.
0557   bool is_profiled() const {
0558     assert(is_tree());
0559     return rep_.cordz_info() != kNullCordzInfo;
0560   }
0561 
0562   // Returns true if either of the provided instances hold a cordz_info value.
0563   // This method is more efficient than the equivalent `data1.is_profiled() ||
0564   // data2.is_profiled()`. Requires both arguments to hold a tree.
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   // Returns the cordz_info sampling instance for this instance, or nullptr
0573   // if the current instance is not sampled and does not have CordzInfo data.
0574   // Requires the current instance to hold a tree value.
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   // Sets the current cordz_info sampling instance for this instance, or nullptr
0584   // if the current instance is not sampled and does not have CordzInfo data.
0585   // Requires the current instance to hold a tree value.
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   // Resets the current cordz_info to null / empty.
0594   void clear_cordz_info() {
0595     assert(is_tree());
0596     rep_.set_cordz_info(kNullCordzInfo);
0597   }
0598 
0599   // Returns a read only pointer to the character data inside this instance.
0600   // Requires the current instance to hold inline data.
0601   const char* as_chars() const {
0602     assert(!is_tree());
0603     return rep_.as_chars();
0604   }
0605 
0606   // Returns a mutable pointer to the character data inside this instance.
0607   // Should be used for 'write only' operations setting an inlined value.
0608   // Applications can set the value of inlined data either before or after
0609   // setting the inlined size, i.e., both of the below are valid:
0610   //
0611   //   // Set inlined data and inline size
0612   //   memcpy(data_.as_chars(), data, size);
0613   //   data_.set_inline_size(size);
0614   //
0615   //   // Set inlined size and inline data
0616   //   data_.set_inline_size(size);
0617   //   memcpy(data_.as_chars(), data, size);
0618   //
0619   // It's an error to read from the returned pointer without a preceding write
0620   // if the current instance does not hold inline data, i.e.: is_tree() == true.
0621   char* as_chars() { return rep_.as_chars(); }
0622 
0623   // Returns the tree value of this value.
0624   // Requires the current instance to hold a tree value.
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   // Initialize this instance to holding the tree value `rep`,
0644   // initializing the cordz_info to null, i.e.: 'not profiled'.
0645   void make_tree(CordRep* rep) {
0646     unpoison();
0647     rep_.make_tree(rep);
0648   }
0649 
0650   // Set the tree value of this instance to 'rep`.
0651   // Requires the current instance to already hold a tree value.
0652   // Does not affect the value of cordz_info.
0653   void set_tree(CordRep* rep) {
0654     assert(is_tree());
0655     rep_.set_tree(rep);
0656   }
0657 
0658   // Returns the size of the inlined character data inside this instance.
0659   // Requires the current instance to hold inline data.
0660   size_t inline_size() const { return rep_.inline_size(); }
0661 
0662   // Sets the size of the inlined character data inside this instance.
0663   // Requires `size` to be <= kMaxInline.
0664   // See the documentation on 'as_chars()' for more information and examples.
0665   void set_inline_size(size_t size) {
0666     unpoison();
0667     rep_.set_inline_size(size);
0668     poison();
0669   }
0670 
0671   // Compares 'this' inlined data  with rhs. The comparison is a straightforward
0672   // lexicographic comparison. `Compare()` returns values as follows:
0673   //
0674   //   -1  'this' InlineData instance is smaller
0675   //    0  the InlineData instances are equal
0676   //    1  'this' InlineData instance larger
0677   int Compare(const InlineData& rhs) const {
0678     return Compare(rep_.SanitizerSafeCopy(), rhs.rep_.SanitizerSafeCopy());
0679   }
0680 
0681  private:
0682   struct Rep {
0683     // See cordz_info_t for forced alignment and size of `cordz_info` details.
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     // Disable sanitizer as we must always be able to read `tag`.
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     // If the data has length <= kMaxInline, we store it in `data`, and
0767     // store the size in the first char of `data` shifted left + 1.
0768     // Else we store it in a tree and store a pointer to that tree in
0769     // `as_tree.rep` with a tagged pointer to make `tag() & 1` non zero.
0770     union {
0771       char data[kMaxInline + 1];
0772       AsTree as_tree;
0773     };
0774 
0775     // TODO(b/145829486): see swap(InlineData, InlineData) for more info.
0776     inline void SwapValue(Rep rhs, Rep& refrhs) {
0777       memcpy(&refrhs, this, sizeof(*this));
0778       memcpy(this, &rhs, sizeof(*this));
0779     }
0780   };
0781 
0782   // Private implementation of `Compare()`
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  // ABSL_INTERNAL_CORD_HAVE_SANITIZER
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  // ABSL_INTERNAL_CORD_HAVE_SANITIZER
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   // ABSL_ASSUME is a workaround for
0879   // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105585
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   // Expect refcount to be 0. Avoiding the cost of an atomic decrement should
0888   // typically outweigh the cost of an extra branch checking for ref == 1.
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   // TODO(b/145829486): `std::swap(lhs.rep_, rhs.rep_)` results in bad codegen
0898   // on clang, spilling the temporary swap value on the stack. Since `Rep` is
0899   // trivial, we can make clang DTRT by calling a hand-rolled `SwapValue` where
0900   // we pass `rhs` both by value (register allocated) and by reference. The IR
0901   // then folds and inlines correctly into an optimized swap without spill.
0902   lhs.rep_.SwapValue(rhs.rep_, rhs.rep_);
0903   rhs.poison();
0904   lhs.poison();
0905 }
0906 
0907 }  // namespace cord_internal
0908 
0909 ABSL_NAMESPACE_END
0910 }  // namespace absl
0911 #endif  // ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_