about summary refs log tree commit diff
path: root/absl/strings/cord.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/cord.cc')
-rw-r--r--absl/strings/cord.cc65
1 files changed, 65 insertions, 0 deletions
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index 1ddd6aec91ab..68f5398791db 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -705,6 +705,37 @@ Cord::Cord(absl::string_view src) {
   }
 }
 
+template <typename T, Cord::EnableIfString<T>>
+Cord::Cord(T&& src) {
+  if (
+      // String is short: copy data to avoid external block overhead.
+      src.size() <= kMaxBytesToCopy ||
+      // String is wasteful: copy data to avoid pinning too much unused memory.
+      src.size() < src.capacity() / 2
+  ) {
+    if (src.size() <= InlineRep::kMaxInline) {
+      contents_.set_data(src.data(), src.size(), false);
+    } else {
+      contents_.set_tree(NewTree(src.data(), src.size(), 0));
+    }
+  } else {
+    struct StringReleaser {
+      void operator()(absl::string_view /* data */) {}
+      std::string data;
+    };
+    const absl::string_view original_data = src;
+    CordRepExternal* rep =
+        static_cast<CordRepExternal*>(absl::cord_internal::NewExternalRep(
+            original_data, StringReleaser{std::move(src)}));
+    // Moving src may have invalidated its data pointer, so adjust it.
+    rep->base =
+        static_cast<StringReleaser*>(GetExternalReleaser(rep))->data.data();
+    contents_.set_tree(rep);
+  }
+}
+
+template Cord::Cord(std::string&& src);
+
 // The destruction code is separate so that the compiler can determine
 // that it does not need to call the destructor on a moved-from Cord.
 void Cord::DestroyCordSlow() {
@@ -742,6 +773,18 @@ Cord& Cord::operator=(absl::string_view src) {
   return *this;
 }
 
+template <typename T, Cord::EnableIfString<T>>
+Cord& Cord::operator=(T&& src) {
+  if (src.size() <= kMaxBytesToCopy) {
+    *this = absl::string_view(src);
+  } else {
+    *this = Cord(std::move(src));
+  }
+  return *this;
+}
+
+template Cord& Cord::operator=(std::string&& src);
+
 // TODO(sanjay): Move to Cord::InlineRep section of file.  For now,
 // we keep it here to make diffs easier.
 void Cord::InlineRep::AppendArray(const char* src_data, size_t src_size) {
@@ -853,6 +896,17 @@ void Cord::Append(const Cord& src) { AppendImpl(src); }
 
 void Cord::Append(Cord&& src) { AppendImpl(std::move(src)); }
 
+template <typename T, Cord::EnableIfString<T>>
+void Cord::Append(T&& src) {
+  if (src.size() <= kMaxBytesToCopy) {
+    Append(absl::string_view(src));
+  } else {
+    Append(Cord(std::move(src)));
+  }
+}
+
+template void Cord::Append(std::string&& src);
+
 void Cord::Prepend(const Cord& src) {
   CordRep* src_tree = src.contents_.tree();
   if (src_tree != nullptr) {
@@ -882,6 +936,17 @@ void Cord::Prepend(absl::string_view src) {
   }
 }
 
+template <typename T, Cord::EnableIfString<T>>
+inline void Cord::Prepend(T&& src) {
+  if (src.size() <= kMaxBytesToCopy) {
+    Prepend(absl::string_view(src));
+  } else {
+    Prepend(Cord(std::move(src)));
+  }
+}
+
+template void Cord::Prepend(std::string&& src);
+
 static CordRep* RemovePrefixFrom(CordRep* node, size_t n) {
   if (n >= node->length) return nullptr;
   if (n == 0) return Ref(node);