about summary refs log tree commit diff
path: root/third_party/abseil_cpp/absl/strings/cord.h
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/abseil_cpp/absl/strings/cord.h')
-rw-r--r--third_party/abseil_cpp/absl/strings/cord.h206
1 files changed, 92 insertions, 114 deletions
diff --git a/third_party/abseil_cpp/absl/strings/cord.h b/third_party/abseil_cpp/absl/strings/cord.h
index dc987454fa..5d5c897e66 100644
--- a/third_party/abseil_cpp/absl/strings/cord.h
+++ b/third_party/abseil_cpp/absl/strings/cord.h
@@ -71,7 +71,6 @@
 #include <type_traits>
 
 #include "absl/base/internal/endian.h"
-#include "absl/base/internal/invoke.h"
 #include "absl/base/internal/per_thread_tls.h"
 #include "absl/base/macros.h"
 #include "absl/base/port.h"
@@ -80,6 +79,7 @@
 #include "absl/meta/type_traits.h"
 #include "absl/strings/internal/cord_internal.h"
 #include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/internal/string_constant.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
 
@@ -126,9 +126,9 @@ class Cord {
       absl::enable_if_t<std::is_same<T, std::string>::value, int>;
 
  public:
-  // Cord::Cord() Constructors
+  // Cord::Cord() Constructors.
 
-  // Creates an empty Cord
+  // Creates an empty Cord.
   constexpr Cord() noexcept;
 
   // Creates a Cord from an existing Cord. Cord is copyable and efficiently
@@ -154,7 +154,7 @@ class Cord {
 
   // Cord::~Cord()
   //
-  // Destructs the Cord
+  // Destructs the Cord.
   ~Cord() {
     if (contents_.is_tree()) DestroyCordSlow();
   }
@@ -173,10 +173,6 @@ class Cord {
   //
   //   * be move constructible
   //   * support `void operator()(absl::string_view) const` or `void operator()`
-  //   * not have alignment requirement greater than what is guaranteed by
-  //     `::operator new`. This alignment is dictated by
-  //     `alignof(std::max_align_t)` (pre-C++17 code) or
-  //     `__STDCPP_DEFAULT_NEW_ALIGNMENT__` (C++17 code).
   //
   // Example:
   //
@@ -592,7 +588,7 @@ class Cord {
 
   // Cord::operator[]
   //
-  // Get the "i"th character of the Cord and returns it, provided that
+  // Gets the "i"th character of the Cord and returns it, provided that
   // 0 <= i < Cord.size().
   //
   // NOTE: This routine is reasonably efficient. It is roughly
@@ -604,8 +600,8 @@ class Cord {
 
   // Cord::TryFlat()
   //
-  // If this cord's representation is a single flat array, return a
-  // string_view referencing that array.  Otherwise return nullopt.
+  // If this cord's representation is a single flat array, returns a
+  // string_view referencing that array.  Otherwise returns nullopt.
   absl::optional<absl::string_view> TryFlat() const;
 
   // Cord::Flatten()
@@ -615,7 +611,7 @@ class Cord {
   // If the cord was already flat, the contents are not modified.
   absl::string_view Flatten();
 
-  // Support absl::Cord as a sink object for absl::Format().
+  // Supports absl::Cord as a sink object for absl::Format().
   friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) {
     cord->Append(part);
   }
@@ -629,12 +625,20 @@ class Cord {
     return c.HashFragmented(std::move(hash_state));
   }
 
+  // Create a Cord with the contents of StringConstant<T>::value.
+  // No allocations will be done and no data will be copied.
+  // This is an INTERNAL API and subject to change or removal. This API can only
+  // be used by spelling absl::strings_internal::MakeStringConstant, which is
+  // also an internal API.
+  template <typename T>
+  explicit constexpr Cord(strings_internal::StringConstant<T>);
+
  private:
   friend class CordTestPeer;
   friend bool operator==(const Cord& lhs, const Cord& rhs);
   friend bool operator==(const Cord& lhs, absl::string_view rhs);
 
-  // Call the provided function once for each cord chunk, in order.  Unlike
+  // Calls the provided function once for each cord chunk, in order.  Unlike
   // Chunks(), this API will not allocate memory.
   void ForEachChunk(absl::FunctionRef<void(absl::string_view)>) const;
 
@@ -649,19 +653,19 @@ class Cord {
   // InlineRep holds either a tree pointer, or an array of kMaxInline bytes.
   class InlineRep {
    public:
-    static constexpr unsigned char kMaxInline = 15;
+    static constexpr unsigned char kMaxInline = cord_internal::kMaxInline;
     static_assert(kMaxInline >= sizeof(absl::cord_internal::CordRep*), "");
-    // Tag byte & kMaxInline means we are storing a pointer.
-    static constexpr unsigned char kTreeFlag = 1 << 4;
-    // Tag byte & kProfiledFlag means we are profiling the Cord.
-    static constexpr unsigned char kProfiledFlag = 1 << 5;
+    static constexpr unsigned char kTreeFlag = cord_internal::kTreeFlag;
+    static constexpr unsigned char kProfiledFlag = cord_internal::kProfiledFlag;
 
-    constexpr InlineRep() : data_{} {}
+    constexpr InlineRep() : data_() {}
     InlineRep(const InlineRep& src);
     InlineRep(InlineRep&& src);
     InlineRep& operator=(const InlineRep& src);
     InlineRep& operator=(InlineRep&& src) noexcept;
 
+    explicit constexpr InlineRep(cord_internal::InlineData data);
+
     void Swap(InlineRep* rhs);
     bool empty() const;
     size_t size() const;
@@ -678,7 +682,7 @@ class Cord {
     void replace_tree(absl::cord_internal::CordRep* rep);
     // Returns non-null iff was holding a pointer
     absl::cord_internal::CordRep* clear();
-    // Convert to pointer if necessary
+    // Converts to pointer if necessary.
     absl::cord_internal::CordRep* force_tree(size_t extra_hint);
     void reduce_size(size_t n);  // REQUIRES: holding data
     void remove_prefix(size_t n);  // REQUIRES: holding data
@@ -689,16 +693,16 @@ class Cord {
     void GetAppendRegion(char** region, size_t* size, size_t max_length);
     void GetAppendRegion(char** region, size_t* size);
     bool IsSame(const InlineRep& other) const {
-      return memcmp(data_, other.data_, sizeof(data_)) == 0;
+      return memcmp(&data_, &other.data_, sizeof(data_)) == 0;
     }
     int BitwiseCompare(const InlineRep& other) const {
       uint64_t x, y;
-      // Use memcpy to avoid anti-aliasing issues.
-      memcpy(&x, data_, sizeof(x));
-      memcpy(&y, other.data_, sizeof(y));
+      // Use memcpy to avoid aliasing issues.
+      memcpy(&x, &data_, sizeof(x));
+      memcpy(&y, &other.data_, sizeof(y));
       if (x == y) {
-        memcpy(&x, data_ + 8, sizeof(x));
-        memcpy(&y, other.data_ + 8, sizeof(y));
+        memcpy(&x, reinterpret_cast<const char*>(&data_) + 8, sizeof(x));
+        memcpy(&y, reinterpret_cast<const char*>(&other.data_) + 8, sizeof(y));
         if (x == y) return 0;
       }
       return absl::big_endian::FromHost64(x) < absl::big_endian::FromHost64(y)
@@ -711,16 +715,16 @@ class Cord {
       // to 15 bytes does not cause a memory allocation.
       absl::strings_internal::STLStringResizeUninitialized(dst,
                                                            sizeof(data_) - 1);
-      memcpy(&(*dst)[0], data_, sizeof(data_) - 1);
+      memcpy(&(*dst)[0], &data_, sizeof(data_) - 1);
       // erase is faster than resize because the logic for memory allocation is
       // not needed.
-      dst->erase(data_[kMaxInline]);
+      dst->erase(tagged_size());
     }
 
     // Copies the inline contents into `dst`. Assumes the cord is not empty.
     void CopyToArray(char* dst) const;
 
-    bool is_tree() const { return data_[kMaxInline] > kMaxInline; }
+    bool is_tree() const { return tagged_size() > kMaxInline; }
 
    private:
     friend class Cord;
@@ -729,21 +733,29 @@ class Cord {
     // Unrefs the tree, stops profiling, and zeroes the contents
     void ClearSlow();
 
-    // If the data has length <= kMaxInline, we store it in data_[0..len-1],
-    // and store the length in data_[kMaxInline].  Else we store it in a tree
-    // and store a pointer to that tree in data_[0..sizeof(CordRep*)-1].
-    alignas(absl::cord_internal::CordRep*) char data_[kMaxInline + 1];
+    void ResetToEmpty() { data_ = {}; }
+
+    // This uses reinterpret_cast instead of the union to avoid accessing the
+    // inactive union element. The tagged size is not a common prefix.
+    void set_tagged_size(char new_tag) {
+      reinterpret_cast<char*>(&data_)[kMaxInline] = new_tag;
+    }
+    char tagged_size() const {
+      return reinterpret_cast<const char*>(&data_)[kMaxInline];
+    }
+
+    cord_internal::InlineData data_;
   };
   InlineRep contents_;
 
-  // Helper for MemoryUsage()
+  // Helper for MemoryUsage().
   static size_t MemoryUsageAux(const absl::cord_internal::CordRep* rep);
 
-  // Helper for GetFlat() and TryFlat()
+  // Helper for GetFlat() and TryFlat().
   static bool GetFlatAux(absl::cord_internal::CordRep* rep,
                          absl::string_view* fragment);
 
-  // Helper for ForEachChunk()
+  // Helper for ForEachChunk().
   static void ForEachChunkAux(
       absl::cord_internal::CordRep* rep,
       absl::FunctionRef<void(absl::string_view)> callback);
@@ -772,11 +784,11 @@ class Cord {
   absl::cord_internal::CordRep* TakeRep() const&;
   absl::cord_internal::CordRep* TakeRep() &&;
 
-  // Helper for Append()
+  // Helper for Append().
   template <typename C>
   void AppendImpl(C&& src);
 
-  // Helper for AbslHashValue()
+  // Helper for AbslHashValue().
   template <typename H>
   H HashFragmented(H hash_state) const {
     typename H::AbslInternalPiecewiseCombiner combiner;
@@ -842,47 +854,15 @@ inline void SmallMemmove(char* dst, const char* src, size_t n,
   }
 }
 
-struct ExternalRepReleaserPair {
-  CordRep* rep;
-  void* releaser_address;
-};
-
-// Allocates a new external `CordRep` and returns a pointer to it and a pointer
-// to `releaser_size` bytes where the desired releaser can be constructed.
+// Does non-template-specific `CordRepExternal` initialization.
 // Expects `data` to be non-empty.
-ExternalRepReleaserPair NewExternalWithUninitializedReleaser(
-    absl::string_view data, ExternalReleaserInvoker invoker,
-    size_t releaser_size);
-
-struct Rank1 {};
-struct Rank0 : Rank1 {};
-
-template <typename Releaser, typename = ::absl::base_internal::InvokeT<
-                                 Releaser, absl::string_view>>
-void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view data) {
-  ::absl::base_internal::Invoke(std::forward<Releaser>(releaser), data);
-}
-
-template <typename Releaser,
-          typename = ::absl::base_internal::InvokeT<Releaser>>
-void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view) {
-  ::absl::base_internal::Invoke(std::forward<Releaser>(releaser));
-}
+void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep);
 
 // Creates a new `CordRep` that owns `data` and `releaser` and returns a pointer
 // to it, or `nullptr` if `data` was empty.
 template <typename Releaser>
 // NOLINTNEXTLINE - suppress clang-tidy raw pointer return.
 CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) {
-  static_assert(
-#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
-      alignof(Releaser) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__,
-#else
-      alignof(Releaser) <= alignof(max_align_t),
-#endif
-      "Releasers with alignment requirement greater than what is returned by "
-      "default `::operator new()` are not supported.");
-
   using ReleaserType = absl::decay_t<Releaser>;
   if (data.empty()) {
     // Never create empty external nodes.
@@ -891,18 +871,10 @@ CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) {
     return nullptr;
   }
 
-  auto releaser_invoker = [](void* type_erased_releaser, absl::string_view d) {
-    auto* my_releaser = static_cast<ReleaserType*>(type_erased_releaser);
-    InvokeReleaser(Rank0{}, std::move(*my_releaser), d);
-    my_releaser->~ReleaserType();
-    return sizeof(Releaser);
-  };
-
-  ExternalRepReleaserPair external = NewExternalWithUninitializedReleaser(
-      data, releaser_invoker, sizeof(releaser));
-  ::new (external.releaser_address)
-      ReleaserType(std::forward<Releaser>(releaser));
-  return external.rep;
+  CordRepExternal* rep = new CordRepExternalImpl<ReleaserType>(
+      std::forward<Releaser>(releaser), 0);
+  InitializeCordRepExternal(data, rep);
+  return rep;
 }
 
 // Overload for function reference types that dispatches using a function
@@ -923,13 +895,16 @@ Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) {
   return cord;
 }
 
+constexpr Cord::InlineRep::InlineRep(cord_internal::InlineData data)
+    : data_(data) {}
+
 inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) {
-  cord_internal::SmallMemmove(data_, src.data_, sizeof(data_));
+  data_ = src.data_;
 }
 
 inline Cord::InlineRep::InlineRep(Cord::InlineRep&& src) {
-  memcpy(data_, src.data_, sizeof(data_));
-  memset(src.data_, 0, sizeof(data_));
+  data_ = src.data_;
+  src.ResetToEmpty();
 }
 
 inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) {
@@ -937,7 +912,7 @@ inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) {
     return *this;
   }
   if (!is_tree() && !src.is_tree()) {
-    cord_internal::SmallMemmove(data_, src.data_, sizeof(data_));
+    data_ = src.data_;
     return *this;
   }
   AssignSlow(src);
@@ -949,8 +924,8 @@ inline Cord::InlineRep& Cord::InlineRep::operator=(
   if (is_tree()) {
     ClearSlow();
   }
-  memcpy(data_, src.data_, sizeof(data_));
-  memset(src.data_, 0, sizeof(data_));
+  data_ = src.data_;
+  src.ResetToEmpty();
   return *this;
 }
 
@@ -959,43 +934,39 @@ inline void Cord::InlineRep::Swap(Cord::InlineRep* rhs) {
     return;
   }
 
-  Cord::InlineRep tmp;
-  cord_internal::SmallMemmove(tmp.data_, data_, sizeof(data_));
-  cord_internal::SmallMemmove(data_, rhs->data_, sizeof(data_));
-  cord_internal::SmallMemmove(rhs->data_, tmp.data_, sizeof(data_));
+  std::swap(data_, rhs->data_);
 }
 
 inline const char* Cord::InlineRep::data() const {
-  return is_tree() ? nullptr : data_;
+  return is_tree() ? nullptr : data_.as_chars;
 }
 
 inline absl::cord_internal::CordRep* Cord::InlineRep::tree() const {
   if (is_tree()) {
-    absl::cord_internal::CordRep* rep;
-    memcpy(&rep, data_, sizeof(rep));
-    return rep;
+    return data_.as_tree.rep;
   } else {
     return nullptr;
   }
 }
 
-inline bool Cord::InlineRep::empty() const { return data_[kMaxInline] == 0; }
+inline bool Cord::InlineRep::empty() const { return tagged_size() == 0; }
 
 inline size_t Cord::InlineRep::size() const {
-  const char tag = data_[kMaxInline];
+  const char tag = tagged_size();
   if (tag <= kMaxInline) return tag;
   return static_cast<size_t>(tree()->length);
 }
 
 inline void Cord::InlineRep::set_tree(absl::cord_internal::CordRep* rep) {
   if (rep == nullptr) {
-    memset(data_, 0, sizeof(data_));
+    ResetToEmpty();
   } else {
     bool was_tree = is_tree();
-    memcpy(data_, &rep, sizeof(rep));
-    memset(data_ + sizeof(rep), 0, sizeof(data_) - sizeof(rep) - 1);
+    data_.as_tree = {rep, {}, tagged_size()};
     if (!was_tree) {
-      data_[kMaxInline] = kTreeFlag;
+      // If we were not a tree already, set the tag.
+      // Otherwise, leave it alone because it might have the profile bit on.
+      set_tagged_size(kTreeFlag);
     }
   }
 }
@@ -1006,29 +977,36 @@ inline void Cord::InlineRep::replace_tree(absl::cord_internal::CordRep* rep) {
     set_tree(rep);
     return;
   }
-  memcpy(data_, &rep, sizeof(rep));
-  memset(data_ + sizeof(rep), 0, sizeof(data_) - sizeof(rep) - 1);
+  data_.as_tree = {rep, {}, tagged_size()};
 }
 
 inline absl::cord_internal::CordRep* Cord::InlineRep::clear() {
-  const char tag = data_[kMaxInline];
-  absl::cord_internal::CordRep* result = nullptr;
-  if (tag > kMaxInline) {
-    memcpy(&result, data_, sizeof(result));
-  }
-  memset(data_, 0, sizeof(data_));  // Clear the cord
+  absl::cord_internal::CordRep* result = tree();
+  ResetToEmpty();
   return result;
 }
 
 inline void Cord::InlineRep::CopyToArray(char* dst) const {
   assert(!is_tree());
-  size_t n = data_[kMaxInline];
+  size_t n = tagged_size();
   assert(n != 0);
-  cord_internal::SmallMemmove(dst, data_, n);
+  cord_internal::SmallMemmove(dst, data_.as_chars, n);
 }
 
 constexpr inline Cord::Cord() noexcept {}
 
+template <typename T>
+constexpr Cord::Cord(strings_internal::StringConstant<T>)
+    : contents_(strings_internal::StringConstant<T>::value.size() <=
+                        cord_internal::kMaxInline
+                    ? cord_internal::InlineData(
+                          strings_internal::StringConstant<T>::value)
+                    : cord_internal::InlineData(cord_internal::AsTree{
+                          &cord_internal::ConstInitExternalStorage<
+                              strings_internal::StringConstant<T>>::value,
+                          {},
+                          cord_internal::kTreeFlag})) {}
+
 inline Cord& Cord::operator=(const Cord& x) {
   contents_ = x.contents_;
   return *this;