15 #include "absl/strings/cord.h"
25 #include <type_traits>
29 #include "gmock/gmock.h"
30 #include "gtest/gtest.h"
31 #include "absl/base/casts.h"
32 #include "absl/base/config.h"
33 #include "absl/base/internal/endian.h"
34 #include "absl/base/internal/raw_logging.h"
35 #include "absl/base/macros.h"
36 #include "absl/container/fixed_array.h"
37 #include "absl/hash/hash.h"
38 #include "absl/random/random.h"
39 #include "absl/strings/cord_test_helpers.h"
40 #include "absl/strings/cordz_test_helpers.h"
41 #include "absl/strings/match.h"
42 #include "absl/strings/str_cat.h"
43 #include "absl/strings/str_format.h"
44 #include "absl/strings/string_view.h"
67 if (upper_bound > 0) {
68 std::uniform_int_distribution<int> uniform(0, upper_bound - 1);
76 if (upper_bound > 0) {
77 std::uniform_int_distribution<size_t> uniform(0, upper_bound - 1);
87 return (*rng)() & mask;
92 std::bernoulli_distribution one_in_1k(0.001);
93 std::bernoulli_distribution one_in_10k(0.0001);
95 if (one_in_10k(*rng)) {
97 }
else if (one_in_1k(*rng)) {
107 std::uniform_int_distribution<int> chars(
'a',
'z');
109 [&]() { return static_cast<char>(chars(*rng)); });
131 for (
int i = 0;
i < 1000;
i++) {
132 char c =
'a' +
i % 26;
142 const size_t max_size = s.size() / 5;
143 size_t min_size = max_size;
144 while (j < s.size()) {
146 if (
N > (s.size() - j)) {
153 std::bernoulli_distribution coin_flip(0.5);
154 if (coin_flip(*rng)) {
167 char*
data =
new char[
str.size()];
204 static bool IsTree(
const Cord& c) {
return c.contents_.is_tree(); }
208 return c.contents_.cordz_info();
214 "Can not be hardened");
234 c.SetExpectedChecksum(1);
244 switch (param.
param) {
248 return "BtreeHardened";
269 size_t last_size = 0;
292 for (
size_t size = 8192;
size <= 256 * 1024;
size += 4 * 1024) {
302 CordRep::Unref(flat);
306 CordRep::Unref(flat);
313 CordRep::Unref(flat);
317 const size_t kMaxSize = 256 * 1024;
323 CordRep::Unref(flat);
330 for (
size_t s = 0; s < CordTestAccess::MaxFlatLength(); s++) {
333 while (src.size() < s) {
334 src.push_back(
'a' + (src.size() % 26));
347 const size_t one_gig = 1024U * 1024U * 1024U;
348 size_t max_size = 2 * one_gig;
349 if (
sizeof(max_size) > 4) max_size = 128 * one_gig;
351 size_t length = 128 * 1024;
364 while (
c.size() < max_size) {
373 for (
int i = 0;
i < 1024; ++
i) {
400 ASSERT_EQ(
x.ExpectedChecksum(), absl::nullopt);
420 std::vector<std::pair<absl::string_view, absl::string_view>>
421 test_string_pairs = {{
"hi there",
"foo"},
422 {
"loooooong coooooord",
"short cord"},
423 {
"short cord",
"loooooong coooooord"},
424 {
"loooooong coooooord1",
"loooooong coooooord2"}};
425 for (std::pair<absl::string_view, absl::string_view> test_strings :
430 tmp = test_strings.second;
438 absl::Cord my_big_cord(
"loooooong coooooord");
445 *my_small_alias =
std::move(my_small_cord);
496 std::set<size_t> positions;
497 for (
int i = 0;
i <= 32; ++
i) {
499 positions.insert(
i * 32 - 1);
500 positions.insert(
i * 32);
501 positions.insert(
i * 32 + 1);
502 positions.insert(
a.size() -
i);
504 positions.insert(237);
505 positions.insert(732);
506 for (
size_t pos : positions) {
507 if (
pos >
a.size())
continue;
508 for (
size_t end_pos : positions) {
509 if (end_pos < pos || end_pos >
a.size())
continue;
514 if (
pos != 0 || end_pos !=
a.size()) {
523 for (
size_t pos = 0;
pos <= sh.size(); ++
pos) {
524 for (
size_t n = 0;
n <= sh.size() -
pos; ++
n) {
533 while (sa.
size() > 1) {
535 ss = ss.substr(1, ss.size() - 2);
537 if (HasFailure())
break;
541 sa =
a.Subcord(0,
a.size() + 1);
545 sa =
a.Subcord(
a.size() + 1, 0);
547 sa =
a.Subcord(
a.size() + 1, 1);
559 ASSERT_EQ(
x.ExpectedChecksum(), absl::nullopt);
567 ASSERT_EQ(
y.ExpectedChecksum(), absl::nullopt);
578 constexpr
size_t kInitialLength = 1024;
579 std::string has_initial_contents(kInitialLength,
'x');
580 const char* address_before_copy = has_initial_contents.data();
584 if (cord.
size() <= kInitialLength) {
585 EXPECT_EQ(has_initial_contents.data(), address_before_copy)
586 <<
"CopyCordToString allocated new string storage; "
587 "has_initial_contents = \""
588 << has_initial_contents <<
"\"";
597 "copying ",
"to ",
"a ",
"string."})));
659 constexpr
size_t kMaxDelta = 128 + 32;
662 constexpr
size_t kMaxDelta = 128 + 32 + 256;
698 buffer.SetLength(s1.size());
706 buffer.SetLength(s2.size());
720 buffer.SetLength(s1.size());
728 buffer.SetLength(s2.size());
745 for (
int size : {6, kInlinedSize - 3, kInlinedSize - 2, 1000}) {
760 for (
size_t dist_from_max = 0; dist_from_max <= 4; ++dist_from_max) {
802 for (
int num_flats : {2, 3, 100}) {
807 for (
int i = 0;
i < num_flats - 1; ++
i) {
825 for (
int i = 0;
i < 2; ++
i) {
952 return c.chunk_begin() ==
c.chunk_end() || ++
c.chunk_begin() ==
c.chunk_end();
958 bool already_flat_and_non_empty =
IsFlat(
c) && !
c.empty();
959 if (already_flat_and_non_empty) {
960 old_flat = *
c.chunk_begin();
970 if (already_flat_and_non_empty) {
972 <<
"Allocated new memory even though the Cord was already flat.";
983 MaybeHardened(
absl::Cord(
"larger than small buffer optimization")));
996 std::vector<std::string>
data_;
1013 for (
int i = 0;
i < 30;
i++) {
1014 data_.push_back(MakeString(
i));
1021 for (
int i = -10;
i <= +10;
i++) {
1022 data_.push_back(MakeString(kHalf +
i));
1025 for (
int i = -10;
i <= +10;
i++) {
1030 size_t size()
const {
return data_.size(); }
1037 for (
size_t i = 0;
i <
d.size();
i++) {
1068 for (
size_t j = 0; j <
d.size(); j++) {
1145 c.RemoveSuffix(200);
1256 blob = SpliceCord(blob, 0,
block);
1259 struct CordCompareTestCase {
1260 template <
typename LHS,
typename RHS>
1261 CordCompareTestCase(
const LHS& lhs,
const RHS& rhs,
bool use_crc)
1262 : lhs_cord(lhs), rhs_cord(rhs) {
1264 lhs_cord.SetExpectedChecksum(1);
1272 const auto sign = [](
int x) {
return x == 0 ? 0 : (
x > 0 ? 1 : -1); };
1274 void VerifyComparison(
const CordCompareTestCase& test_case) {
1277 int expected = sign(lhs_string.compare(rhs_string));
1278 EXPECT_EQ(expected, test_case.lhs_cord.Compare(test_case.rhs_cord))
1279 <<
"LHS=" << lhs_string <<
"; RHS=" << rhs_string;
1280 EXPECT_EQ(expected, test_case.lhs_cord.Compare(rhs_string))
1281 <<
"LHS=" << lhs_string <<
"; RHS=" << rhs_string;
1282 EXPECT_EQ(-expected, test_case.rhs_cord.Compare(test_case.lhs_cord))
1283 <<
"LHS=" << rhs_string <<
"; RHS=" << lhs_string;
1284 EXPECT_EQ(-expected, test_case.rhs_cord.Compare(lhs_string))
1285 <<
"LHS=" << rhs_string <<
"; RHS=" << lhs_string;
1290 subcord = subcord.Subcord(3, 10);
1293 tmp.Append(
"BBBBBBBBBBBBBBBB");
1295 concat.
Append(
"DDDDDDDDDDDDDDDD");
1299 concat2.Append(
"aaaBBBBBBBBBBBBBBBBccccc");
1300 concat2.Append(
"cccccccccccDDDDDDDDDDDDDD");
1301 concat2.Append(
"DD");
1303 const bool use_crc = UseCrc();
1305 std::vector<CordCompareTestCase>
test_cases = {{
1307 {
"abcdef",
"abcdef", use_crc},
1308 {
"abcdef",
"abcdee", use_crc},
1309 {
"abcdef",
"abcdeg", use_crc},
1310 {
"bbcdef",
"abcdef", use_crc},
1311 {
"bbcdef",
"abcdeg", use_crc},
1312 {
"abcdefa",
"abcdef", use_crc},
1313 {
"abcdef",
"abcdefa", use_crc},
1316 {
"aaaaaBBBBBcccccDDDDD",
"aaaaaBBBBBcccccDDDDD", use_crc},
1317 {
"aaaaaBBBBBcccccDDDDD",
"aaaaaBBBBBxccccDDDDD", use_crc},
1318 {
"aaaaaBBBBBcxcccDDDDD",
"aaaaaBBBBBcccccDDDDD", use_crc},
1319 {
"aaaaaBBBBBxccccDDDDD",
"aaaaaBBBBBcccccDDDDX", use_crc},
1320 {
"aaaaaBBBBBcccccDDDDDa",
"aaaaaBBBBBcccccDDDDD", use_crc},
1321 {
"aaaaaBBBBBcccccDDDDD",
"aaaaaBBBBBcccccDDDDDa", use_crc},
1324 {subcord, subcord, use_crc},
1325 {subcord,
"aaBBBBBccc", use_crc},
1326 {subcord,
"aaBBBBBccd", use_crc},
1327 {subcord,
"aaBBBBBccb", use_crc},
1328 {subcord,
"aaBBBBBxcb", use_crc},
1329 {subcord,
"aaBBBBBccca", use_crc},
1330 {subcord,
"aaBBBBBcc", use_crc},
1333 {concat, concat, use_crc},
1335 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDDD",
1338 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBcccccccccccccccxDDDDDDDDDDDDDDDD",
1341 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBacccccccccccccccDDDDDDDDDDDDDDDD",
1344 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDD",
1347 "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDDDe",
1350 {concat, concat2, use_crc},
1354 VerifyComparison(tc);
1379 typedef std::basic_string<uint8_t> ustring;
1384 int expected = sign(
cs.compare(ds));
1390 std::uniform_int_distribution<uint32_t> uniform_uint8(0, 255);
1391 char x =
static_cast<char>(uniform_uint8(rng));
1415 for (
int j = 0;
j < (
i % 7) + 1;
j++) {
1419 std::bernoulli_distribution coin_flip(0.5);
1427 template <
typename T1,
typename T2>
1428 void CompareOperators() {
1458 CompareOperators<absl::Cord, absl::Cord>();
1462 CompareOperators<absl::Cord, absl::string_view>();
1466 CompareOperators<absl::string_view, absl::Cord>();
1470 CompareOperators<absl::Cord, std::string>();
1474 CompareOperators<std::string, absl::Cord>();
1478 CompareOperators<std::string, absl::Cord>();
1482 CompareOperators<absl::Cord, std::string>();
1486 CompareOperators<const char*, absl::Cord>();
1490 CompareOperators<absl::Cord, const char*>();
1496 bool invoked =
false;
1510 bool invoked =
false;
1520 bool invoked =
false;
1554 constexpr
size_t kLength = 256;
1556 std::array<char, kLength> data_array;
1557 for (
size_t i = 0;
i < kLength; ++
i) data_array[
i] =
data[
i];
1558 bool invoked =
false;
1569 static bool invoked;
1586 explicit Releaser(
bool* invoked) : invoked(invoked) {}
1587 Releaser(Releaser&& other) noexcept : invoked(other.invoked) {}
1593 bool invoked =
false;
1599 bool invoked =
false;
1600 (void)MaybeHardened(
1606 bool invoked =
false;
1612 TEST_P(
CordTest, ConstructFromExternalNonTrivialReleaserDestructor) {
1614 explicit Releaser(
bool* destroyed) : destroyed(destroyed) {}
1615 ~Releaser() { *destroyed =
true; }
1621 bool destroyed =
false;
1622 Releaser releaser(&destroyed);
1627 TEST_P(
CordTest, ConstructFromExternalReferenceQualifierOverloads) {
1628 enum InvokedAs { kMissing, kLValue, kRValue };
1631 CopiedAs copied_as =
kNone;
1632 InvokedAs invoked_as = kMissing;
1634 void Record(InvokedAs rhs) {
1639 void Record(CopiedAs rhs) {
1640 if (copied_as == kNone || rhs == kCopy) copied_as = rhs;
1647 Releaser(Releaser&& rhs) : tr_(rhs.tr_) { tr_->Record(kMove); }
1648 Releaser(
const Releaser& rhs) : tr_(rhs.tr_) { tr_->Record(kCopy); }
1657 const Releaser releaser1(&
tracker);
1662 const Releaser releaser2(&
tracker);
1677 const Releaser releaser5(&
tracker);
1689 static const char* strings[] = {
"",
"hello",
"there"};
1690 for (
const char*
str : strings) {
1695 dst.Append(
"(suffix)");
1726 for (
int i = 0;
i <
s.size();
i++) {
1758 const size_t expected =
1766 const size_t flat_size =
1775 const size_t flat_size =
1787 const size_t flat_size =
1797 const size_t flat_size =
1808 EXPECT_EQ(cord2.EstimatedMemoryUsage(kFairShare),
1814 size_t flats1_size = 0;
1815 absl::Cord flats1[4] = {MakeCord(1000,
'a'), MakeCord(1100,
'a'),
1816 MakeCord(1200,
'a'), MakeCord(1300,
'a')};
1831 size_t rep1_shared_size =
sizeof(
CordRepBtree) + flats1_size / 2;
1838 size_t flats2_size = 0;
1839 absl::Cord flats2[4] = {MakeCord(600,
'a'), MakeCord(700,
'a'),
1840 MakeCord(800,
'a'), MakeCord(900,
'a')};
1869 c2.Append(small_string);
1871 EXPECT_EQ(
c1.EstimatedMemoryUsage(),
c2.EstimatedMemoryUsage());
1881 s1.
Append(
"abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefg");
1903 for (
char c : expected) {
1922 if (
sizeof(
size_t) > 4) {
1934 const size_t s1 = (1
u << 31) - 1;
1938 const size_t s2 = 600;
1953 const size_t acceptable_delta =
1965 while (control_data.length() < 0x4000) {
1968 control_data.append(control_data);
1977 MaybeHarden(fragmented);
1979 EXPECT_EQ(
"A fragmented Cord", fragmented);
1996 std::vector<absl::string_view> chunks = {
"A ",
"fragmented ",
"Cord"};
1999 MaybeHarden(fragmented);
2001 EXPECT_EQ(
"A fragmented Cord", fragmented);
2029 std::iterator_traits<absl::Cord::ChunkIterator>::iterator_category,
2030 std::input_iterator_tag>::
value,
2038 std::iterator_traits<absl::Cord::ChunkIterator>::difference_type,
2042 std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::pointer,
2046 std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::reference,
2052 size_t expected_chunks) {
2063 size_t n_chunks = 0;
2071 EXPECT_EQ(pre_iter->data(), (*pre_iter).data());
2072 EXPECT_EQ(pre_iter->size(), (*pre_iter).size());
2079 int n_equal_iterators = 0;
2082 n_equal_iterators +=
static_cast<int>(
it == pre_iter);
2103 MaybeHarden(small_buffer_cord);
2106 absl::Cord flat_node_cord(
"larger than small buffer optimization");
2107 MaybeHarden(flat_node_cord);
2111 {
"a ",
"small ",
"fragmented ",
"cord ",
"for ",
2112 "testing ",
"chunk ",
"iterations."})),
2117 MaybeHarden(reused_nodes_cord);
2119 size_t expected_chunks = 3;
2120 for (
int i = 0;
i < 8; ++
i) {
2121 reused_nodes_cord.
Prepend(reused_nodes_cord);
2122 MaybeHarden(reused_nodes_cord);
2123 expected_chunks *= 2;
2138 for (
bool as_flat : {
true,
false}) {
2145 #if !defined(NDEBUG) || ABSL_OPTION_HARDENED
2172 for (
bool as_flat : {
true,
false}) {
2178 cord = cord.
Subcord(200, 2000);
2181 auto it = cord.Chars().begin();
2182 #if !defined(NDEBUG) || ABSL_OPTION_HARDENED
2186 it = cord.Chars().begin();
2191 it = cord.Chars().begin();
2197 EXPECT_EQ(frag, substr.substr(200, 1500));
2201 EXPECT_EQ(frag, substr.substr(1700, 300));
2218 std::iterator_traits<absl::Cord::CharIterator>::iterator_category,
2219 std::input_iterator_tag>::
value,
2227 std::iterator_traits<absl::Cord::CharIterator>::difference_type,
2231 std::is_same<std::iterator_traits<absl::Cord::CharIterator>::pointer,
2232 const char*>::
value,
2235 std::is_same<std::iterator_traits<absl::Cord::CharIterator>::reference,
2236 const char&>::
value,
2263 EXPECT_EQ(&*pre_iter, pre_iter.operator->());
2265 const char* character_address = &*pre_iter;
2268 EXPECT_EQ(character_address, &*pre_iter);
2270 int n_equal_iterators = 0;
2272 n_equal_iterators +=
static_cast<int>(
it == pre_iter);
2280 advance_iter =
range.begin();
2284 advance_iter = pre_iter;
2288 advance_iter = pre_iter;
2307 while (!chunk.empty()) {
2309 chunk.remove_prefix(1);
2320 MaybeHarden(small_buffer_cord);
2323 absl::Cord flat_node_cord(
"larger than small buffer optimization");
2324 MaybeHarden(flat_node_cord);
2329 "testing ",
"character ",
"iteration."})));
2334 for (
int i = 0;
i < 4; ++
i) {
2335 reused_nodes_cord.
Prepend(reused_nodes_cord);
2336 MaybeHarden(reused_nodes_cord);
2343 for (
int i = 0;
i < 4; ++
i) {
2345 MaybeHarden(subcords);
2357 constexpr
int kBlocks = 6;
2358 constexpr
size_t kBlockSize = 2500;
2359 constexpr
size_t kChunkSize1 = 1500;
2360 constexpr
size_t kChunkSize2 = 2500;
2361 constexpr
size_t kChunkSize3 = 3000;
2362 constexpr
size_t kChunkSize4 = 150;
2366 for (
int i = 0;
i < kBlocks; ++
i) {
2373 for (
size_t chunk_size :
2374 {kChunkSize1, kChunkSize2, kChunkSize3, kChunkSize4}) {
2378 const size_t n = std::min<size_t>(
data.length() -
offset, chunk_size);
2391 std::stringstream
output;
2399 std::vector<std::string> cord_chunks;
2406 std::vector<std::string> iterated_chunks;
2409 iterated_chunks.emplace_back(sv);
2411 EXPECT_EQ(iterated_chunks, cord_chunks);
2426 <<
"pos = " <<
pos <<
"; count = " <<
count;
2434 EXPECT_EQ(
c,
"There were 0003 little pigs.");
2438 EXPECT_EQ(
c,
"There were 0003 little pigs.And 1 bad wolf!");
2449 bool test_hardening =
false;
2452 test_hardening =
true;
2455 if (!test_hardening)
return;
2479 for (
int i = 0;
i < 1000000; ++
i) {
2483 for (
int j = 0; j < 1000; ++j) {
2531 template <
typename Str>
2541 template <
typename Str>
2550 static bool init_exit_tester = exit_tester.
Set(&cord, expected);
2551 (void)init_exit_tester;
2566 for (
int i = 0;
i < 10; ++
i) {
2576 for (
int i = 0;
i < 10; ++
i) {
2614 class PopulatedCordFactory {
2630 PopulatedCordFactory cord_factories[] = {
2643 {
"external substring", [] {
2656 std::vector<std::string> fragments(200, fragment);
2658 assert(cord.
size() == 40000);
2670 :
name_(
name), mutate_(mutate), undo_(undo) {}
2673 void Mutate(
absl::Cord& cord)
const { mutate_(cord); }
2674 bool CanUndo()
const {
return undo_ !=
nullptr; }
2675 void Undo(
absl::Cord& cord)
const { undo_(cord); }
2685 CordMutator cord_mutators[] ={
2687 {
"overwrite", [](
absl::Cord&
c) {
c =
"overwritten"; }},
2701 "append checksummed cord",
2705 c.Append(to_append);
2727 "prepend checksummed cord",
2731 c.Prepend(to_prepend);
2740 {
"remove prefix", [](
absl::Cord&
c) {
c.RemovePrefix(2); }},
2741 {
"remove suffix", [](
absl::Cord&
c) {
c.RemoveSuffix(2); }},
2742 {
"subcord", [](
absl::Cord&
c) {
c =
c.Subcord(1,
c.size() - 2); }},
2762 for (
const PopulatedCordFactory& factory : cord_factories) {
2764 for (
bool shared : {
false,
true}) {
2767 absl::Cord shared_cord_source = factory.Generate();
2768 auto make_instance = [=] {
2769 return shared ? shared_cord_source : factory.Generate();
2772 const absl::Cord base_value = factory.Generate();
2773 const std::string base_value_as_string(factory.Generate().Flatten());
2779 c1.SetExpectedChecksum(12345);
2780 EXPECT_EQ(
c1.ExpectedChecksum().value_or(0), 12345);
2788 c1_copy_assign =
c1;
2794 EXPECT_EQ(
c1.ExpectedChecksum().value_or(0), 12345);
2799 for (
const CordMutator& mutator : cord_mutators) {
2804 c2.SetExpectedChecksum(24680);
2809 if (mutator.CanUndo()) {
2844 bool first_pass =
true;