summaryrefslogtreecommitdiff
path: root/absl/strings
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings')
-rw-r--r--absl/strings/cord.cc11
-rw-r--r--absl/strings/cord_test.cc53
-rw-r--r--absl/strings/internal/cord_rep_btree.h1
-rw-r--r--absl/strings/internal/str_format/bind.h2
4 files changed, 58 insertions, 9 deletions
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index e9d72fa8..115705a2 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -689,13 +689,10 @@ void Cord::InlineRep::AppendArray(absl::string_view src,
return;
}
- // Note: we don't concern ourselves if src aliases data stored in the
- // inlined data of 'this', as we update the InlineData only at the end.
- // We are going from an inline size to beyond inline size. Make the new size
- // either double the inlined size, or the added size + 10%.
- const size_t size1 = inline_length * 2 + src.size();
- const size_t size2 = inline_length + src.size() / 10;
- rep = CordRepFlat::New(std::max<size_t>(size1, size2));
+ // Allocate flat to be a perfect fit on first append exceeding inlined size.
+ // Subsequent growth will use amortized growth until we reach maximum flat
+ // size.
+ rep = CordRepFlat::New(inline_length + src.size());
appended = std::min(src.size(), rep->flat()->Capacity() - inline_length);
memcpy(rep->flat()->Data(), data_.as_chars(), inline_length);
memcpy(rep->flat()->Data() + inline_length, src.data(), appended);
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc
index d0296338..06a7bd6c 100644
--- a/absl/strings/cord_test.cc
+++ b/absl/strings/cord_test.cc
@@ -1385,6 +1385,59 @@ TEST_P(CordTest, DiabolicalGrowth) {
cord.EstimatedMemoryUsage());
}
+// The following tests check support for >4GB cords in 64-bit binaries, and
+// 2GB-4GB cords in 32-bit binaries. This function returns the large cord size
+// that's appropriate for the binary.
+
+// Construct a huge cord with the specified valid prefix.
+static absl::Cord MakeHuge(absl::string_view prefix) {
+ absl::Cord cord;
+ if (sizeof(size_t) > 4) {
+ // In 64-bit binaries, test 64-bit Cord support.
+ const size_t size =
+ static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 314;
+ cord.Append(absl::MakeCordFromExternal(
+ absl::string_view(prefix.data(), size),
+ [](absl::string_view s) { DoNothing(s, nullptr); }));
+ } else {
+ // Cords are limited to 32-bit lengths in 32-bit binaries. The following
+ // tests check for use of "signed int" to represent Cord length/offset.
+ // However absl::string_view does not allow lengths >= (1u<<31), so we need
+ // to append in two parts;
+ const size_t s1 = (1u << 31) - 1;
+ // For shorter cord, `Append` copies the data rather than allocating a new
+ // node. The threshold is currently set to 511, so `s2` needs to be bigger
+ // to not trigger the copy.
+ const size_t s2 = 600;
+ cord.Append(absl::MakeCordFromExternal(
+ absl::string_view(prefix.data(), s1),
+ [](absl::string_view s) { DoNothing(s, nullptr); }));
+ cord.Append(absl::MakeCordFromExternal(
+ absl::string_view("", s2),
+ [](absl::string_view s) { DoNothing(s, nullptr); }));
+ }
+ return cord;
+}
+
+TEST_P(CordTest, HugeCord) {
+ absl::Cord cord = MakeHuge("huge cord");
+ EXPECT_LE(cord.size(), cord.EstimatedMemoryUsage());
+ EXPECT_GE(cord.size() + 100, cord.EstimatedMemoryUsage());
+}
+
+// Tests that Append() works ok when handed a self reference
+TEST_P(CordTest, AppendSelf) {
+ // We run the test until data is ~16K
+ // This guarantees it covers small, medium and large data.
+ std::string control_data = "Abc";
+ absl::Cord data(control_data);
+ while (control_data.length() < 0x4000) {
+ data.Append(data);
+ control_data.append(control_data);
+ ASSERT_EQ(control_data, data);
+ }
+}
+
TEST_P(CordTest, MakeFragmentedCordFromInitializerList) {
absl::Cord fragmented =
absl::MakeFragmentedCord({"A ", "fragmented ", "Cord"});
diff --git a/absl/strings/internal/cord_rep_btree.h b/absl/strings/internal/cord_rep_btree.h
index 303f4580..bbaa7934 100644
--- a/absl/strings/internal/cord_rep_btree.h
+++ b/absl/strings/internal/cord_rep_btree.h
@@ -23,7 +23,6 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/base/optimization.h"
#include "absl/strings/internal/cord_internal.h"
-#include "absl/strings/internal/cord_rep_btree.h"
#include "absl/strings/internal/cord_rep_flat.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h
index 267cc0ef..b26cff66 100644
--- a/absl/strings/internal/str_format/bind.h
+++ b/absl/strings/internal/str_format/bind.h
@@ -100,7 +100,7 @@ class FormatSpecTemplate
// We use the 'unavailable' attribute to give a better compiler error than
// just 'method is deleted'.
// To avoid checking the format twice, we just check that the format is
- // constexpr. If is it valid, then the overload below will kick in.
+ // constexpr. If it is valid, then the overload below will kick in.
// We add the template here to make this overload have lower priority.
template <typename = void>
FormatSpecTemplate(const char* s) // NOLINT