about summary refs log tree commit diff
path: root/absl/strings
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings')
-rw-r--r--absl/strings/cord.cc65
-rw-r--r--absl/strings/cord.h27
-rw-r--r--absl/strings/internal/str_format/convert_test.cc6
-rw-r--r--absl/strings/internal/str_format/float_conversion.cc12
-rw-r--r--absl/strings/str_format.h2
-rw-r--r--absl/strings/str_format_test.cc2
-rw-r--r--absl/strings/str_split.h1
7 files changed, 86 insertions, 29 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);
diff --git a/absl/strings/cord.h b/absl/strings/cord.h
index 3be8d7d875f5..dc987454fafb 100644
--- a/absl/strings/cord.h
+++ b/absl/strings/cord.h
@@ -147,11 +147,8 @@ class Cord {
   // Creates a Cord from a `std::string&&` rvalue. These constructors are
   // templated to avoid ambiguities for types that are convertible to both
   // `absl::string_view` and `std::string`, such as `const char*`.
-  //
-  // Note that these functions reserve the right to use the `string&&`'s
-  // memory and that they will do so in the future.
   template <typename T, EnableIfString<T> = 0>
-  explicit Cord(T&& src) : Cord(absl::string_view(src)) {}
+  explicit Cord(T&& src);
   template <typename T, EnableIfString<T> = 0>
   Cord& operator=(T&& src);
 
@@ -1048,11 +1045,8 @@ inline Cord& Cord::operator=(Cord&& x) noexcept {
   return *this;
 }
 
-template <typename T, Cord::EnableIfString<T>>
-inline Cord& Cord::operator=(T&& src) {
-  *this = absl::string_view(src);
-  return *this;
-}
+extern template Cord::Cord(std::string&& src);
+extern template Cord& Cord::operator=(std::string&& src);
 
 inline size_t Cord::size() const {
   // Length is 1st field in str.rep_
@@ -1098,19 +1092,8 @@ inline void Cord::Append(absl::string_view src) {
   contents_.AppendArray(src.data(), src.size());
 }
 
-template <typename T, Cord::EnableIfString<T>>
-inline void Cord::Append(T&& src) {
-  // Note that this function reserves the right to reuse the `string&&`'s
-  // memory and that it will do so in the future.
-  Append(absl::string_view(src));
-}
-
-template <typename T, Cord::EnableIfString<T>>
-inline void Cord::Prepend(T&& src) {
-  // Note that this function reserves the right to reuse the `string&&`'s
-  // memory and that it will do so in the future.
-  Prepend(absl::string_view(src));
-}
+extern template void Cord::Append(std::string&& src);
+extern template void Cord::Prepend(std::string&& src);
 
 inline int Cord::Compare(const Cord& rhs) const {
   if (!contents_.is_tree() && !rhs.contents_.is_tree()) {
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index 20c6229fcb37..0e8535c27b7a 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -764,6 +764,12 @@ TEST_F(FormatConvertTest, LongDouble) {
     }
   }
 
+  // Regression tests
+  //
+  // Using a string literal because not all platforms support hex literals or it
+  // might be out of range.
+  doubles.push_back(std::strtold("-0xf.ffffffb5feafffbp-16324L", nullptr));
+
   for (const char *fmt : kFormats) {
     for (char f : {'f', 'F',  //
                    'g', 'G',  //
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc
index a761a5a5f9ce..10e4695411b2 100644
--- a/absl/strings/internal/str_format/float_conversion.cc
+++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -224,13 +224,13 @@ class FractionalDigitGenerator {
   // This function will allocate enough stack space to perform the conversion.
   static void RunConversion(
       uint128 v, int exp, absl::FunctionRef<void(FractionalDigitGenerator)> f) {
+    using Limits = std::numeric_limits<long double>;
     assert(-exp < 0);
-    assert(-exp >= std::numeric_limits<long double>::min_exponent - 128);
-    static_assert(
-        StackArray::kMaxCapacity >=
-            (128 - std::numeric_limits<long double>::min_exponent + 31) / 32,
-        "");
-    StackArray::RunWithCapacity((exp + 31) / 32,
+    assert(-exp >= Limits::min_exponent - 128);
+    static_assert(StackArray::kMaxCapacity >=
+                      (Limits::digits + 128 - Limits::min_exponent + 31) / 32,
+                  "");
+    StackArray::RunWithCapacity((Limits::digits + exp + 31) / 32,
                                 [=](absl::Span<uint32_t> input) {
                                   f(FractionalDigitGenerator(input, v, exp));
                                 });
diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h
index f833a80aba63..36bd84a3e60b 100644
--- a/absl/strings/str_format.h
+++ b/absl/strings/str_format.h
@@ -19,7 +19,7 @@
 //
 // The `str_format` library is a typesafe replacement for the family of
 // `printf()` string formatting routines within the `<cstdio>` standard library
-// header. Like the `printf` family, the `str_format` uses a "format string" to
+// header. Like the `printf` family, `str_format` uses a "format string" to
 // perform argument substitutions based on types. See the `FormatSpec` section
 // below for format string documentation.
 //
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
index 49a68849f064..22cfef66d5d4 100644
--- a/absl/strings/str_format_test.cc
+++ b/absl/strings/str_format_test.cc
@@ -8,6 +8,7 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/strings/cord.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 
@@ -353,6 +354,7 @@ TEST(StrFormat, BehavesAsDocumented) {
   EXPECT_EQ(StrFormat("%s", "C"), "C");
   EXPECT_EQ(StrFormat("%s", std::string("C++")), "C++");
   EXPECT_EQ(StrFormat("%s", string_view("view")), "view");
+  EXPECT_EQ(StrFormat("%s", absl::Cord("cord")), "cord");
   // Integral Conversion
   //     These format integral types: char, int, long, uint64_t, etc.
   EXPECT_EQ(StrFormat("%d", char{10}), "10");
diff --git a/absl/strings/str_split.h b/absl/strings/str_split.h
index a79cd4a0ce0d..1ce17f38aa81 100644
--- a/absl/strings/str_split.h
+++ b/absl/strings/str_split.h
@@ -44,6 +44,7 @@
 #include <vector>
 
 #include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
 #include "absl/strings/internal/str_split_internal.h"
 #include "absl/strings/string_view.h"
 #include "absl/strings/strip.h"