| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582 | #include "absl/strings/cord.h"#include <algorithm>#include <climits>#include <cstdio>#include <iterator>#include <map>#include <numeric>#include <random>#include <sstream>#include <type_traits>#include <utility>#include <vector>#include "gmock/gmock.h"#include "gtest/gtest.h"#include "absl/base/casts.h"#include "absl/base/config.h"#include "absl/base/internal/endian.h"#include "absl/base/internal/raw_logging.h"#include "absl/container/fixed_array.h"#include "absl/strings/cord_test_helpers.h"#include "absl/strings/str_cat.h"#include "absl/strings/string_view.h"typedef std::mt19937_64 RandomEngine;static std::string RandomLowercaseString(RandomEngine* rng);static std::string RandomLowercaseString(RandomEngine* rng, size_t length);static int GetUniformRandomUpTo(RandomEngine* rng, int upper_bound) {  if (upper_bound > 0) {    std::uniform_int_distribution<int> uniform(0, upper_bound - 1);    return uniform(*rng);  } else {    return 0;  }}static size_t GetUniformRandomUpTo(RandomEngine* rng, size_t upper_bound) {  if (upper_bound > 0) {    std::uniform_int_distribution<size_t> uniform(0, upper_bound - 1);    return uniform(*rng);  } else {    return 0;  }}static int32_t GenerateSkewedRandom(RandomEngine* rng, int max_log) {  const uint32_t base = (*rng)() % (max_log + 1);  const uint32_t mask = ((base < 32) ? (1u << base) : 0u) - 1u;  return (*rng)() & mask;}static std::string RandomLowercaseString(RandomEngine* rng) {  int length;  std::bernoulli_distribution one_in_1k(0.001);  std::bernoulli_distribution one_in_10k(0.0001);  // With low probability, make a large fragment  if (one_in_10k(*rng)) {    length = GetUniformRandomUpTo(rng, 1048576);  } else if (one_in_1k(*rng)) {    length = GetUniformRandomUpTo(rng, 10000);  } else {    length = GenerateSkewedRandom(rng, 10);  }  return RandomLowercaseString(rng, length);}static std::string RandomLowercaseString(RandomEngine* rng, size_t length) {  std::string result(length, '\0');  std::uniform_int_distribution<int> chars('a', 'z');  std::generate(result.begin(), result.end(),                [&]() { return static_cast<char>(chars(*rng)); });  return result;}static void DoNothing(absl::string_view /* data */, void* /* arg */) {}static void DeleteExternalString(absl::string_view data, void* arg) {  std::string* s = reinterpret_cast<std::string*>(arg);  EXPECT_EQ(data, *s);  delete s;}// Add "s" to *dst via `MakeCordFromExternal`static void AddExternalMemory(absl::string_view s, absl::Cord* dst) {  std::string* str = new std::string(s.data(), s.size());  dst->Append(absl::MakeCordFromExternal(*str, [str](absl::string_view data) {    DeleteExternalString(data, str);  }));}static void DumpGrowth() {  absl::Cord str;  for (int i = 0; i < 1000; i++) {    char c = 'a' + i % 26;    str.Append(absl::string_view(&c, 1));  }}// Make a Cord with some number of fragments.  Return the size (in bytes)// of the smallest fragment.static size_t AppendWithFragments(const std::string& s, RandomEngine* rng,                                  absl::Cord* cord) {  size_t j = 0;  const size_t max_size = s.size() / 5;  // Make approx. 10 fragments  size_t min_size = max_size;            // size of smallest fragment  while (j < s.size()) {    size_t N = 1 + GetUniformRandomUpTo(rng, max_size);    if (N > (s.size() - j)) {      N = s.size() - j;    }    if (N < min_size) {      min_size = N;    }    std::bernoulli_distribution coin_flip(0.5);    if (coin_flip(*rng)) {      // Grow by adding an external-memory.      AddExternalMemory(absl::string_view(s.data() + j, N), cord);    } else {      cord->Append(absl::string_view(s.data() + j, N));    }    j += N;  }  return min_size;}// Add an external memory that contains the specified std::string to cordstatic void AddNewStringBlock(const std::string& str, absl::Cord* dst) {  char* data = new char[str.size()];  memcpy(data, str.data(), str.size());  dst->Append(absl::MakeCordFromExternal(      absl::string_view(data, str.size()),      [](absl::string_view s) { delete[] s.data(); }));}// Make a Cord out of many different types of nodes.static absl::Cord MakeComposite() {  absl::Cord cord;  cord.Append("the");  AddExternalMemory(" quick brown", &cord);  AddExternalMemory(" fox jumped", &cord);  absl::Cord full(" over");  AddExternalMemory(" the lazy", &full);  AddNewStringBlock(" dog slept the whole day away", &full);  absl::Cord substring = full.Subcord(0, 18);  // Make substring long enough to defeat the copying fast path in Append.  substring.Append(std::string(1000, '.'));  cord.Append(substring);  cord = cord.Subcord(0, cord.size() - 998);  // Remove most of extra junk  return cord;}namespace absl {ABSL_NAMESPACE_BEGINclass CordTestPeer { public:  static void ForEachChunk(      const Cord& c, absl::FunctionRef<void(absl::string_view)> callback) {    c.ForEachChunk(callback);  }};ABSL_NAMESPACE_END}  // namespace abslTEST(Cord, AllFlatSizes) {  using absl::strings_internal::CordTestAccess;  for (size_t s = 0; s < CordTestAccess::MaxFlatLength(); s++) {    // Make a string of length s.    std::string src;    while (src.size() < s) {      src.push_back('a' + (src.size() % 26));    }    absl::Cord dst(src);    EXPECT_EQ(std::string(dst), src) << s;  }}// We create a Cord at least 128GB in size using the fact that Cords can// internally reference-count; thus the Cord is enormous without actually// consuming very much memory.TEST(GigabyteCord, FromExternal) {  const size_t one_gig = 1024U * 1024U * 1024U;  size_t max_size = 2 * one_gig;  if (sizeof(max_size) > 4) max_size = 128 * one_gig;  size_t length = 128 * 1024;  char* data = new char[length];  absl::Cord from = absl::MakeCordFromExternal(      absl::string_view(data, length),      [](absl::string_view sv) { delete[] sv.data(); });  // This loop may seem odd due to its combination of exponential doubling of  // size and incremental size increases.  We do it incrementally to be sure the  // Cord will need rebalancing and will exercise code that, in the past, has  // caused crashes in production.  We grow exponentially so that the code will  // execute in a reasonable amount of time.  absl::Cord c;  ABSL_RAW_LOG(INFO, "Made a Cord with %zu bytes!", c.size());  c.Append(from);  while (c.size() < max_size) {    c.Append(c);    c.Append(from);    c.Append(from);    c.Append(from);    c.Append(from);  }  for (int i = 0; i < 1024; ++i) {    c.Append(from);  }  ABSL_RAW_LOG(INFO, "Made a Cord with %zu bytes!", c.size());  // Note: on a 32-bit build, this comes out to   2,818,048,000 bytes.  // Note: on a 64-bit build, this comes out to 171,932,385,280 bytes.}static absl::Cord MakeExternalCord(int size) {  char* buffer = new char[size];  memset(buffer, 'x', size);  absl::Cord cord;  cord.Append(absl::MakeCordFromExternal(      absl::string_view(buffer, size),      [](absl::string_view s) { delete[] s.data(); }));  return cord;}// Extern to fool clang that this is not constant. Needed to suppress// a warning of unsafe code we want to test.extern bool my_unique_true_boolean;bool my_unique_true_boolean = true;TEST(Cord, Assignment) {  absl::Cord x(absl::string_view("hi there"));  absl::Cord y(x);  ASSERT_EQ(std::string(x), "hi there");  ASSERT_EQ(std::string(y), "hi there");  ASSERT_TRUE(x == y);  ASSERT_TRUE(x <= y);  ASSERT_TRUE(y <= x);  x = absl::string_view("foo");  ASSERT_EQ(std::string(x), "foo");  ASSERT_EQ(std::string(y), "hi there");  ASSERT_TRUE(x < y);  ASSERT_TRUE(y > x);  ASSERT_TRUE(x != y);  ASSERT_TRUE(x <= y);  ASSERT_TRUE(y >= x);  x = "foo";  ASSERT_EQ(x, "foo");  // Test that going from inline rep to tree we don't leak memory.  std::vector<std::pair<absl::string_view, absl::string_view>>      test_string_pairs = {{"hi there", "foo"},                           {"loooooong coooooord", "short cord"},                           {"short cord", "loooooong coooooord"},                           {"loooooong coooooord1", "loooooong coooooord2"}};  for (std::pair<absl::string_view, absl::string_view> test_strings :       test_string_pairs) {    absl::Cord tmp(test_strings.first);    absl::Cord z(std::move(tmp));    ASSERT_EQ(std::string(z), test_strings.first);    tmp = test_strings.second;    z = std::move(tmp);    ASSERT_EQ(std::string(z), test_strings.second);  }  {    // Test that self-move assignment doesn't crash/leak.    // Do not write such code!    absl::Cord my_small_cord("foo");    absl::Cord my_big_cord("loooooong coooooord");    // Bypass clang's warning on self move-assignment.    absl::Cord* my_small_alias =        my_unique_true_boolean ? &my_small_cord : &my_big_cord;    absl::Cord* my_big_alias =        !my_unique_true_boolean ? &my_small_cord : &my_big_cord;    *my_small_alias = std::move(my_small_cord);    *my_big_alias = std::move(my_big_cord);    // my_small_cord and my_big_cord are in an unspecified but valid    // state, and will be correctly destroyed here.  }}TEST(Cord, StartsEndsWith) {  absl::Cord x(absl::string_view("abcde"));  absl::Cord empty("");  ASSERT_TRUE(x.StartsWith(absl::Cord("abcde")));  ASSERT_TRUE(x.StartsWith(absl::Cord("abc")));  ASSERT_TRUE(x.StartsWith(absl::Cord("")));  ASSERT_TRUE(empty.StartsWith(absl::Cord("")));  ASSERT_TRUE(x.EndsWith(absl::Cord("abcde")));  ASSERT_TRUE(x.EndsWith(absl::Cord("cde")));  ASSERT_TRUE(x.EndsWith(absl::Cord("")));  ASSERT_TRUE(empty.EndsWith(absl::Cord("")));  ASSERT_TRUE(!x.StartsWith(absl::Cord("xyz")));  ASSERT_TRUE(!empty.StartsWith(absl::Cord("xyz")));  ASSERT_TRUE(!x.EndsWith(absl::Cord("xyz")));  ASSERT_TRUE(!empty.EndsWith(absl::Cord("xyz")));  ASSERT_TRUE(x.StartsWith("abcde"));  ASSERT_TRUE(x.StartsWith("abc"));  ASSERT_TRUE(x.StartsWith(""));  ASSERT_TRUE(empty.StartsWith(""));  ASSERT_TRUE(x.EndsWith("abcde"));  ASSERT_TRUE(x.EndsWith("cde"));  ASSERT_TRUE(x.EndsWith(""));  ASSERT_TRUE(empty.EndsWith(""));  ASSERT_TRUE(!x.StartsWith("xyz"));  ASSERT_TRUE(!empty.StartsWith("xyz"));  ASSERT_TRUE(!x.EndsWith("xyz"));  ASSERT_TRUE(!empty.EndsWith("xyz"));}TEST(Cord, Subcord) {  RandomEngine rng(testing::GTEST_FLAG(random_seed));  const std::string s = RandomLowercaseString(&rng, 1024);  absl::Cord a;  AppendWithFragments(s, &rng, &a);  ASSERT_EQ(s.size(), a.size());  // Check subcords of a, from a variety of interesting points.  std::set<size_t> positions;  for (int i = 0; i <= 32; ++i) {    positions.insert(i);    positions.insert(i * 32 - 1);    positions.insert(i * 32);    positions.insert(i * 32 + 1);    positions.insert(a.size() - i);  }  positions.insert(237);  positions.insert(732);  for (size_t pos : positions) {    if (pos > a.size()) continue;    for (size_t end_pos : positions) {      if (end_pos < pos || end_pos > a.size()) continue;      absl::Cord sa = a.Subcord(pos, end_pos - pos);      EXPECT_EQ(absl::string_view(s).substr(pos, end_pos - pos),                std::string(sa))          << a;    }  }  // Do the same thing for an inline cord.  const std::string sh = "short";  absl::Cord c(sh);  for (size_t pos = 0; pos <= sh.size(); ++pos) {    for (size_t n = 0; n <= sh.size() - pos; ++n) {      absl::Cord sc = c.Subcord(pos, n);      EXPECT_EQ(sh.substr(pos, n), std::string(sc)) << c;    }  }  // Check subcords of subcords.  absl::Cord sa = a.Subcord(0, a.size());  std::string ss = s.substr(0, s.size());  while (sa.size() > 1) {    sa = sa.Subcord(1, sa.size() - 2);    ss = ss.substr(1, ss.size() - 2);    EXPECT_EQ(ss, std::string(sa)) << a;    if (HasFailure()) break;  // halt cascade  }  // It is OK to ask for too much.  sa = a.Subcord(0, a.size() + 1);  EXPECT_EQ(s, std::string(sa));  // It is OK to ask for something beyond the end.  sa = a.Subcord(a.size() + 1, 0);  EXPECT_TRUE(sa.empty());  sa = a.Subcord(a.size() + 1, 1);  EXPECT_TRUE(sa.empty());}TEST(Cord, Swap) {  absl::string_view a("Dexter");  absl::string_view b("Mandark");  absl::Cord x(a);  absl::Cord y(b);  swap(x, y);  ASSERT_EQ(x, absl::Cord(b));  ASSERT_EQ(y, absl::Cord(a));}static void VerifyCopyToString(const absl::Cord& cord) {  std::string initially_empty;  absl::CopyCordToString(cord, &initially_empty);  EXPECT_EQ(initially_empty, cord);  constexpr size_t kInitialLength = 1024;  std::string has_initial_contents(kInitialLength, 'x');  const char* address_before_copy = has_initial_contents.data();  absl::CopyCordToString(cord, &has_initial_contents);  EXPECT_EQ(has_initial_contents, cord);  if (cord.size() <= kInitialLength) {    EXPECT_EQ(has_initial_contents.data(), address_before_copy)        << "CopyCordToString allocated new string storage; "           "has_initial_contents = \""        << has_initial_contents << "\"";  }}TEST(Cord, CopyToString) {  VerifyCopyToString(absl::Cord());  VerifyCopyToString(absl::Cord("small cord"));  VerifyCopyToString(      absl::MakeFragmentedCord({"fragmented ", "cord ", "to ", "test ",                                "copying ", "to ", "a ", "string."}));}TEST(TryFlat, Empty) {  absl::Cord c;  EXPECT_EQ(c.TryFlat(), "");}TEST(TryFlat, Flat) {  absl::Cord c("hello");  EXPECT_EQ(c.TryFlat(), "hello");}TEST(TryFlat, SubstrInlined) {  absl::Cord c("hello");  c.RemovePrefix(1);  EXPECT_EQ(c.TryFlat(), "ello");}TEST(TryFlat, SubstrFlat) {  absl::Cord c("longer than 15 bytes");  c.RemovePrefix(1);  EXPECT_EQ(c.TryFlat(), "onger than 15 bytes");}TEST(TryFlat, Concat) {  absl::Cord c = absl::MakeFragmentedCord({"hel", "lo"});  EXPECT_EQ(c.TryFlat(), absl::nullopt);}TEST(TryFlat, External) {  absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {});  EXPECT_EQ(c.TryFlat(), "hell");}TEST(TryFlat, SubstrExternal) {  absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {});  c.RemovePrefix(1);  EXPECT_EQ(c.TryFlat(), "ell");}TEST(TryFlat, SubstrConcat) {  absl::Cord c = absl::MakeFragmentedCord({"hello", " world"});  c.RemovePrefix(1);  EXPECT_EQ(c.TryFlat(), absl::nullopt);}static bool IsFlat(const absl::Cord& c) {  return c.chunk_begin() == c.chunk_end() || ++c.chunk_begin() == c.chunk_end();}static void VerifyFlatten(absl::Cord c) {  std::string old_contents(c);  absl::string_view old_flat;  bool already_flat_and_non_empty = IsFlat(c) && !c.empty();  if (already_flat_and_non_empty) {    old_flat = *c.chunk_begin();  }  absl::string_view new_flat = c.Flatten();  // Verify that the contents of the flattened Cord are correct.  EXPECT_EQ(new_flat, old_contents);  EXPECT_EQ(std::string(c), old_contents);  // If the Cord contained data and was already flat, verify that the data  // wasn't copied.  if (already_flat_and_non_empty) {    EXPECT_EQ(old_flat.data(), new_flat.data())        << "Allocated new memory even though the Cord was already flat.";  }  // Verify that the flattened Cord is in fact flat.  EXPECT_TRUE(IsFlat(c));}TEST(Cord, Flatten) {  VerifyFlatten(absl::Cord());  VerifyFlatten(absl::Cord("small cord"));  VerifyFlatten(absl::Cord("larger than small buffer optimization"));  VerifyFlatten(absl::MakeFragmentedCord({"small ", "fragmented ", "cord"}));  // Test with a cord that is longer than the largest flat buffer  RandomEngine rng(testing::GTEST_FLAG(random_seed));  VerifyFlatten(absl::Cord(RandomLowercaseString(&rng, 8192)));}// Test datanamespace {class TestData { private:  std::vector<std::string> data_;  // Return a std::string of the specified length.  static std::string MakeString(int length) {    std::string result;    char buf[30];    snprintf(buf, sizeof(buf), "(%d)", length);    while (result.size() < length) {      result += buf;    }    result.resize(length);    return result;  } public:  TestData() {    // short strings increasing in length by one    for (int i = 0; i < 30; i++) {      data_.push_back(MakeString(i));    }    // strings around half kMaxFlatLength    static const int kMaxFlatLength = 4096 - 9;    static const int kHalf = kMaxFlatLength / 2;    for (int i = -10; i <= +10; i++) {      data_.push_back(MakeString(kHalf + i));    }    for (int i = -10; i <= +10; i++) {      data_.push_back(MakeString(kMaxFlatLength + i));    }  }  size_t size() const { return data_.size(); }  const std::string& data(size_t i) const { return data_[i]; }};}  // namespaceTEST(Cord, MultipleLengths) {  TestData d;  for (size_t i = 0; i < d.size(); i++) {    std::string a = d.data(i);    {  // Construct from Cord      absl::Cord tmp(a);      absl::Cord x(tmp);      EXPECT_EQ(a, std::string(x)) << "'" << a << "'";    }    {  // Construct from absl::string_view      absl::Cord x(a);      EXPECT_EQ(a, std::string(x)) << "'" << a << "'";    }    {  // Append cord to self      absl::Cord self(a);      self.Append(self);      EXPECT_EQ(a + a, std::string(self)) << "'" << a << "' + '" << a << "'";    }    {  // Prepend cord to self      absl::Cord self(a);      self.Prepend(self);      EXPECT_EQ(a + a, std::string(self)) << "'" << a << "' + '" << a << "'";    }    // Try to append/prepend others    for (size_t j = 0; j < d.size(); j++) {      std::string b = d.data(j);      {  // CopyFrom Cord        absl::Cord x(a);        absl::Cord y(b);        x = y;        EXPECT_EQ(b, std::string(x)) << "'" << a << "' + '" << b << "'";      }      {  // CopyFrom absl::string_view        absl::Cord x(a);        x = b;        EXPECT_EQ(b, std::string(x)) << "'" << a << "' + '" << b << "'";      }      {  // Cord::Append(Cord)        absl::Cord x(a);        absl::Cord y(b);        x.Append(y);        EXPECT_EQ(a + b, std::string(x)) << "'" << a << "' + '" << b << "'";      }      {  // Cord::Append(absl::string_view)        absl::Cord x(a);        x.Append(b);        EXPECT_EQ(a + b, std::string(x)) << "'" << a << "' + '" << b << "'";      }      {  // Cord::Prepend(Cord)        absl::Cord x(a);        absl::Cord y(b);        x.Prepend(y);        EXPECT_EQ(b + a, std::string(x)) << "'" << b << "' + '" << a << "'";      }      {  // Cord::Prepend(absl::string_view)        absl::Cord x(a);        x.Prepend(b);        EXPECT_EQ(b + a, std::string(x)) << "'" << b << "' + '" << a << "'";      }    }  }}namespace {TEST(Cord, RemoveSuffixWithExternalOrSubstring) {  absl::Cord cord = absl::MakeCordFromExternal(      "foo bar baz", [](absl::string_view s) { DoNothing(s, nullptr); });  EXPECT_EQ("foo bar baz", std::string(cord));  // This RemoveSuffix() will wrap the EXTERNAL node in a SUBSTRING node.  cord.RemoveSuffix(4);  EXPECT_EQ("foo bar", std::string(cord));  // This RemoveSuffix() will adjust the SUBSTRING node in-place.  cord.RemoveSuffix(4);  EXPECT_EQ("foo", std::string(cord));}TEST(Cord, RemoveSuffixMakesZeroLengthNode) {  absl::Cord c;  c.Append(absl::Cord(std::string(100, 'x')));  absl::Cord other_ref = c;  // Prevent inplace appends  c.Append(absl::Cord(std::string(200, 'y')));  c.RemoveSuffix(200);  EXPECT_EQ(std::string(100, 'x'), std::string(c));}}  // namespace// CordSpliceTest contributed by hendrie.namespace {// Create a cord with an external memory block filled with 'z'absl::Cord CordWithZedBlock(size_t size) {  char* data = new char[size];  if (size > 0) {    memset(data, 'z', size);  }  absl::Cord cord = absl::MakeCordFromExternal(      absl::string_view(data, size),      [](absl::string_view s) { delete[] s.data(); });  return cord;}// Establish that ZedBlock does what we think it does.TEST(CordSpliceTest, ZedBlock) {  absl::Cord blob = CordWithZedBlock(10);  EXPECT_EQ(10, blob.size());  std::string s;  absl::CopyCordToString(blob, &s);  EXPECT_EQ("zzzzzzzzzz", s);}TEST(CordSpliceTest, ZedBlock0) {  absl::Cord blob = CordWithZedBlock(0);  EXPECT_EQ(0, blob.size());  std::string s;  absl::CopyCordToString(blob, &s);  EXPECT_EQ("", s);}TEST(CordSpliceTest, ZedBlockSuffix1) {  absl::Cord blob = CordWithZedBlock(10);  EXPECT_EQ(10, blob.size());  absl::Cord suffix(blob);  suffix.RemovePrefix(9);  EXPECT_EQ(1, suffix.size());  std::string s;  absl::CopyCordToString(suffix, &s);  EXPECT_EQ("z", s);}// Remove all of a prefix blockTEST(CordSpliceTest, ZedBlockSuffix0) {  absl::Cord blob = CordWithZedBlock(10);  EXPECT_EQ(10, blob.size());  absl::Cord suffix(blob);  suffix.RemovePrefix(10);  EXPECT_EQ(0, suffix.size());  std::string s;  absl::CopyCordToString(suffix, &s);  EXPECT_EQ("", s);}absl::Cord BigCord(size_t len, char v) {  std::string s(len, v);  return absl::Cord(s);}// Splice block into cord.absl::Cord SpliceCord(const absl::Cord& blob, int64_t offset,                      const absl::Cord& block) {  ABSL_RAW_CHECK(offset >= 0, "");  ABSL_RAW_CHECK(offset + block.size() <= blob.size(), "");  absl::Cord result(blob);  result.RemoveSuffix(blob.size() - offset);  result.Append(block);  absl::Cord suffix(blob);  suffix.RemovePrefix(offset + block.size());  result.Append(suffix);  ABSL_RAW_CHECK(blob.size() == result.size(), "");  return result;}// Taking an empty suffix of a block breaks appending.TEST(CordSpliceTest, RemoveEntireBlock1) {  absl::Cord zero = CordWithZedBlock(10);  absl::Cord suffix(zero);  suffix.RemovePrefix(10);  absl::Cord result;  result.Append(suffix);}TEST(CordSpliceTest, RemoveEntireBlock2) {  absl::Cord zero = CordWithZedBlock(10);  absl::Cord prefix(zero);  prefix.RemoveSuffix(10);  absl::Cord suffix(zero);  suffix.RemovePrefix(10);  absl::Cord result(prefix);  result.Append(suffix);}TEST(CordSpliceTest, RemoveEntireBlock3) {  absl::Cord blob = CordWithZedBlock(10);  absl::Cord block = BigCord(10, 'b');  blob = SpliceCord(blob, 0, block);}struct CordCompareTestCase {  template <typename LHS, typename RHS>  CordCompareTestCase(const LHS& lhs, const RHS& rhs)      : lhs_cord(lhs), rhs_cord(rhs) {}  absl::Cord lhs_cord;  absl::Cord rhs_cord;};const auto sign = [](int x) { return x == 0 ? 0 : (x > 0 ? 1 : -1); };void VerifyComparison(const CordCompareTestCase& test_case) {  std::string lhs_string(test_case.lhs_cord);  std::string rhs_string(test_case.rhs_cord);  int expected = sign(lhs_string.compare(rhs_string));  EXPECT_EQ(expected, test_case.lhs_cord.Compare(test_case.rhs_cord))      << "LHS=" << lhs_string << "; RHS=" << rhs_string;  EXPECT_EQ(expected, test_case.lhs_cord.Compare(rhs_string))      << "LHS=" << lhs_string << "; RHS=" << rhs_string;  EXPECT_EQ(-expected, test_case.rhs_cord.Compare(test_case.lhs_cord))      << "LHS=" << rhs_string << "; RHS=" << lhs_string;  EXPECT_EQ(-expected, test_case.rhs_cord.Compare(lhs_string))      << "LHS=" << rhs_string << "; RHS=" << lhs_string;}TEST(Cord, Compare) {  absl::Cord subcord("aaaaaBBBBBcccccDDDDD");  subcord = subcord.Subcord(3, 10);  absl::Cord tmp("aaaaaaaaaaaaaaaa");  tmp.Append("BBBBBBBBBBBBBBBB");  absl::Cord concat = absl::Cord("cccccccccccccccc");  concat.Append("DDDDDDDDDDDDDDDD");  concat.Prepend(tmp);  absl::Cord concat2("aaaaaaaaaaaaa");  concat2.Append("aaaBBBBBBBBBBBBBBBBccccc");  concat2.Append("cccccccccccDDDDDDDDDDDDDD");  concat2.Append("DD");  std::vector<CordCompareTestCase> test_cases = {{      // Inline cords      {"abcdef", "abcdef"},      {"abcdef", "abcdee"},      {"abcdef", "abcdeg"},      {"bbcdef", "abcdef"},      {"bbcdef", "abcdeg"},      {"abcdefa", "abcdef"},      {"abcdef", "abcdefa"},      // Small flat cords      {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBcccccDDDDD"},      {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBxccccDDDDD"},      {"aaaaaBBBBBcxcccDDDDD", "aaaaaBBBBBcccccDDDDD"},      {"aaaaaBBBBBxccccDDDDD", "aaaaaBBBBBcccccDDDDX"},      {"aaaaaBBBBBcccccDDDDDa", "aaaaaBBBBBcccccDDDDD"},      {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBcccccDDDDDa"},      // Subcords      {subcord, subcord},      {subcord, "aaBBBBBccc"},      {subcord, "aaBBBBBccd"},      {subcord, "aaBBBBBccb"},      {subcord, "aaBBBBBxcb"},      {subcord, "aaBBBBBccca"},      {subcord, "aaBBBBBcc"},      // Concats      {concat, concat},      {concat,       "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDDD"},      {concat,       "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBcccccccccccccccxDDDDDDDDDDDDDDDD"},      {concat,       "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBacccccccccccccccDDDDDDDDDDDDDDDD"},      {concat,       "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDD"},      {concat,       "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDDDe"},      {concat, concat2},  }};  for (const auto& tc : test_cases) {    VerifyComparison(tc);  }}TEST(Cord, CompareAfterAssign) {  absl::Cord a("aaaaaa1111111");  absl::Cord b("aaaaaa2222222");  a = "cccccc";  b = "cccccc";  EXPECT_EQ(a, b);  EXPECT_FALSE(a < b);  a = "aaaa";  b = "bbbbb";  a = "";  b = "";  EXPECT_EQ(a, b);  EXPECT_FALSE(a < b);}// Test CompareTo() and ComparePrefix() against string and substring// comparison methods from basic_string.static void TestCompare(const absl::Cord& c, const absl::Cord& d,                        RandomEngine* rng) {  typedef std::basic_string<uint8_t> ustring;  ustring cs(reinterpret_cast<const uint8_t*>(std::string(c).data()), c.size());  ustring ds(reinterpret_cast<const uint8_t*>(std::string(d).data()), d.size());  // ustring comparison is ideal because we expect Cord comparisons to be  // based on unsigned byte comparisons regardless of whether char is signed.  int expected = sign(cs.compare(ds));  EXPECT_EQ(expected, sign(c.Compare(d))) << c << ", " << d;}TEST(Compare, ComparisonIsUnsigned) {  RandomEngine rng(testing::GTEST_FLAG(random_seed));  std::uniform_int_distribution<uint32_t> uniform_uint8(0, 255);  char x = static_cast<char>(uniform_uint8(rng));  TestCompare(      absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100), x)),      absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100), x ^ 0x80)), &rng);}TEST(Compare, RandomComparisons) {  const int kIters = 5000;  RandomEngine rng(testing::GTEST_FLAG(random_seed));  int n = GetUniformRandomUpTo(&rng, 5000);  absl::Cord a[] = {MakeExternalCord(n),                    absl::Cord("ant"),                    absl::Cord("elephant"),                    absl::Cord("giraffe"),                    absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100),                                           GetUniformRandomUpTo(&rng, 100))),                    absl::Cord(""),                    absl::Cord("x"),                    absl::Cord("A"),                    absl::Cord("B"),                    absl::Cord("C")};  for (int i = 0; i < kIters; i++) {    absl::Cord c, d;    for (int j = 0; j < (i % 7) + 1; j++) {      c.Append(a[GetUniformRandomUpTo(&rng, ABSL_ARRAYSIZE(a))]);      d.Append(a[GetUniformRandomUpTo(&rng, ABSL_ARRAYSIZE(a))]);    }    std::bernoulli_distribution coin_flip(0.5);    TestCompare(coin_flip(rng) ? c : absl::Cord(std::string(c)),                coin_flip(rng) ? d : absl::Cord(std::string(d)), &rng);  }}template <typename T1, typename T2>void CompareOperators() {  const T1 a("a");  const T2 b("b");  EXPECT_TRUE(a == a);  // For pointer type (i.e. `const char*`), operator== compares the address  // instead of the string, so `a == const char*("a")` isn't necessarily true.  EXPECT_TRUE(std::is_pointer<T1>::value || a == T1("a"));  EXPECT_TRUE(std::is_pointer<T2>::value || a == T2("a"));  EXPECT_FALSE(a == b);  EXPECT_TRUE(a != b);  EXPECT_FALSE(a != a);  EXPECT_TRUE(a < b);  EXPECT_FALSE(b < a);  EXPECT_TRUE(b > a);  EXPECT_FALSE(a > b);  EXPECT_TRUE(a >= a);  EXPECT_TRUE(b >= a);  EXPECT_FALSE(a >= b);  EXPECT_TRUE(a <= a);  EXPECT_TRUE(a <= b);  EXPECT_FALSE(b <= a);}TEST(ComparisonOperators, Cord_Cord) {  CompareOperators<absl::Cord, absl::Cord>();}TEST(ComparisonOperators, Cord_StringPiece) {  CompareOperators<absl::Cord, absl::string_view>();}TEST(ComparisonOperators, StringPiece_Cord) {  CompareOperators<absl::string_view, absl::Cord>();}TEST(ComparisonOperators, Cord_string) {  CompareOperators<absl::Cord, std::string>();}TEST(ComparisonOperators, string_Cord) {  CompareOperators<std::string, absl::Cord>();}TEST(ComparisonOperators, stdstring_Cord) {  CompareOperators<std::string, absl::Cord>();}TEST(ComparisonOperators, Cord_stdstring) {  CompareOperators<absl::Cord, std::string>();}TEST(ComparisonOperators, charstar_Cord) {  CompareOperators<const char*, absl::Cord>();}TEST(ComparisonOperators, Cord_charstar) {  CompareOperators<absl::Cord, const char*>();}TEST(ConstructFromExternal, ReleaserInvoked) {  // Empty external memory means the releaser should be called immediately.  {    bool invoked = false;    auto releaser = [&invoked](absl::string_view) { invoked = true; };    {      auto c = absl::MakeCordFromExternal("", releaser);      EXPECT_TRUE(invoked);    }  }  // If the size of the data is small enough, a future constructor  // implementation may copy the bytes and immediately invoke the releaser  // instead of creating an external node. We make a large dummy std::string to  // make this test independent of such an optimization.  std::string large_dummy(2048, 'c');  {    bool invoked = false;    auto releaser = [&invoked](absl::string_view) { invoked = true; };    {      auto c = absl::MakeCordFromExternal(large_dummy, releaser);      EXPECT_FALSE(invoked);    }    EXPECT_TRUE(invoked);  }  {    bool invoked = false;    auto releaser = [&invoked](absl::string_view) { invoked = true; };    {      absl::Cord copy;      {        auto c = absl::MakeCordFromExternal(large_dummy, releaser);        copy = c;        EXPECT_FALSE(invoked);      }      EXPECT_FALSE(invoked);    }    EXPECT_TRUE(invoked);  }}TEST(ConstructFromExternal, CompareContents) {  RandomEngine rng(testing::GTEST_FLAG(random_seed));  for (int length = 1; length <= 2048; length *= 2) {    std::string data = RandomLowercaseString(&rng, length);    auto* external = new std::string(data);    auto cord =        absl::MakeCordFromExternal(*external, [external](absl::string_view sv) {          EXPECT_EQ(external->data(), sv.data());          EXPECT_EQ(external->size(), sv.size());          delete external;        });    EXPECT_EQ(data, cord);  }}TEST(ConstructFromExternal, LargeReleaser) {  RandomEngine rng(testing::GTEST_FLAG(random_seed));  constexpr size_t kLength = 256;  std::string data = RandomLowercaseString(&rng, kLength);  std::array<char, kLength> data_array;  for (size_t i = 0; i < kLength; ++i) data_array[i] = data[i];  bool invoked = false;  auto releaser = [data_array, &invoked](absl::string_view data) {    EXPECT_EQ(data, absl::string_view(data_array.data(), data_array.size()));    invoked = true;  };  (void)absl::MakeCordFromExternal(data, releaser);  EXPECT_TRUE(invoked);}TEST(ConstructFromExternal, FunctionPointerReleaser) {  static absl::string_view data("hello world");  static bool invoked;  auto* releaser =      static_cast<void (*)(absl::string_view)>([](absl::string_view sv) {        EXPECT_EQ(data, sv);        invoked = true;      });  invoked = false;  (void)absl::MakeCordFromExternal(data, releaser);  EXPECT_TRUE(invoked);  invoked = false;  (void)absl::MakeCordFromExternal(data, *releaser);  EXPECT_TRUE(invoked);}TEST(ConstructFromExternal, MoveOnlyReleaser) {  struct Releaser {    explicit Releaser(bool* invoked) : invoked(invoked) {}    Releaser(Releaser&& other) noexcept : invoked(other.invoked) {}    void operator()(absl::string_view) const { *invoked = true; }    bool* invoked;  };  bool invoked = false;  (void)absl::MakeCordFromExternal("dummy", Releaser(&invoked));  EXPECT_TRUE(invoked);}TEST(ConstructFromExternal, NoArgLambda) {  bool invoked = false;  (void)absl::MakeCordFromExternal("dummy", [&invoked]() { invoked = true; });  EXPECT_TRUE(invoked);}TEST(ConstructFromExternal, StringViewArgLambda) {  bool invoked = false;  (void)absl::MakeCordFromExternal(      "dummy", [&invoked](absl::string_view) { invoked = true; });  EXPECT_TRUE(invoked);}TEST(ConstructFromExternal, NonTrivialReleaserDestructor) {  struct Releaser {    explicit Releaser(bool* destroyed) : destroyed(destroyed) {}    ~Releaser() { *destroyed = true; }    void operator()(absl::string_view) const {}    bool* destroyed;  };  bool destroyed = false;  Releaser releaser(&destroyed);  (void)absl::MakeCordFromExternal("dummy", releaser);  EXPECT_TRUE(destroyed);}TEST(ConstructFromExternal, ReferenceQualifierOverloads) {  struct Releaser {    void operator()(absl::string_view) & { *lvalue_invoked = true; }    void operator()(absl::string_view) && { *rvalue_invoked = true; }    bool* lvalue_invoked;    bool* rvalue_invoked;  };  bool lvalue_invoked = false;  bool rvalue_invoked = false;  Releaser releaser = {&lvalue_invoked, &rvalue_invoked};  (void)absl::MakeCordFromExternal("", releaser);  EXPECT_FALSE(lvalue_invoked);  EXPECT_TRUE(rvalue_invoked);  rvalue_invoked = false;  (void)absl::MakeCordFromExternal("dummy", releaser);  EXPECT_FALSE(lvalue_invoked);  EXPECT_TRUE(rvalue_invoked);  rvalue_invoked = false;  // NOLINTNEXTLINE: suppress clang-tidy std::move on trivially copyable type.  (void)absl::MakeCordFromExternal("dummy", std::move(releaser));  EXPECT_FALSE(lvalue_invoked);  EXPECT_TRUE(rvalue_invoked);}TEST(ExternalMemory, BasicUsage) {  static const char* strings[] = {"", "hello", "there"};  for (const char* str : strings) {    absl::Cord dst("(prefix)");    AddExternalMemory(str, &dst);    dst.Append("(suffix)");    EXPECT_EQ((std::string("(prefix)") + str + std::string("(suffix)")),              std::string(dst));  }}TEST(ExternalMemory, RemovePrefixSuffix) {  // Exhaustively try all sub-strings.  absl::Cord cord = MakeComposite();  std::string s = std::string(cord);  for (int offset = 0; offset <= s.size(); offset++) {    for (int length = 0; length <= s.size() - offset; length++) {      absl::Cord result(cord);      result.RemovePrefix(offset);      result.RemoveSuffix(result.size() - length);      EXPECT_EQ(s.substr(offset, length), std::string(result))          << offset << " " << length;    }  }}TEST(ExternalMemory, Get) {  absl::Cord cord("hello");  AddExternalMemory(" world!", &cord);  AddExternalMemory(" how are ", &cord);  cord.Append(" you?");  std::string s = std::string(cord);  for (int i = 0; i < s.size(); i++) {    EXPECT_EQ(s[i], cord[i]);  }}// CordMemoryUsage tests verify the correctness of the EstimatedMemoryUsage()// These tests take into account that the reported memory usage is approximate// and non-deterministic. For all tests, We verify that the reported memory// usage is larger than `size()`, and less than `size() * 1.5` as a cord should// never reserve more 'extra' capacity than half of its size as it grows.// Additionally we have some whiteboxed expectations based on our knowledge of// the layout and size of empty and inlined cords, and flat nodes.TEST(CordMemoryUsage, Empty) {  EXPECT_EQ(sizeof(absl::Cord), absl::Cord().EstimatedMemoryUsage());}TEST(CordMemoryUsage, Embedded) {  absl::Cord a("hello");  EXPECT_EQ(a.EstimatedMemoryUsage(), sizeof(absl::Cord));}TEST(CordMemoryUsage, EmbeddedAppend) {  absl::Cord a("a");  absl::Cord b("bcd");  EXPECT_EQ(b.EstimatedMemoryUsage(), sizeof(absl::Cord));  a.Append(b);  EXPECT_EQ(a.EstimatedMemoryUsage(), sizeof(absl::Cord));}TEST(CordMemoryUsage, ExternalMemory) {  static const int kLength = 1000;  absl::Cord cord;  AddExternalMemory(std::string(kLength, 'x'), &cord);  EXPECT_GT(cord.EstimatedMemoryUsage(), kLength);  EXPECT_LE(cord.EstimatedMemoryUsage(), kLength * 1.5);}TEST(CordMemoryUsage, Flat) {  static const int kLength = 125;  absl::Cord a(std::string(kLength, 'a'));  EXPECT_GT(a.EstimatedMemoryUsage(), kLength);  EXPECT_LE(a.EstimatedMemoryUsage(), kLength * 1.5);}TEST(CordMemoryUsage, AppendFlat) {  using absl::strings_internal::CordTestAccess;  absl::Cord a(std::string(CordTestAccess::MaxFlatLength(), 'a'));  size_t length = a.EstimatedMemoryUsage();  a.Append(std::string(CordTestAccess::MaxFlatLength(), 'b'));  size_t delta = a.EstimatedMemoryUsage() - length;  EXPECT_GT(delta, CordTestAccess::MaxFlatLength());  EXPECT_LE(delta, CordTestAccess::MaxFlatLength() * 1.5);}// Regtest for a change that had to be rolled back because it expanded out// of the InlineRep too soon, which was observable through MemoryUsage().TEST(CordMemoryUsage, InlineRep) {  constexpr size_t kMaxInline = 15;  // Cord::InlineRep::N  const std::string small_string(kMaxInline, 'x');  absl::Cord c1(small_string);  absl::Cord c2;  c2.Append(small_string);  EXPECT_EQ(c1, c2);  EXPECT_EQ(c1.EstimatedMemoryUsage(), c2.EstimatedMemoryUsage());}}  // namespace// Regtest for 7510292 (fix a bug introduced by 7465150)TEST(Cord, Concat_Append) {  // Create a rep of type CONCAT  absl::Cord s1("foobarbarbarbarbar");  s1.Append("abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefg");  size_t size = s1.size();  // Create a copy of s1 and append to it.  absl::Cord s2 = s1;  s2.Append("x");  // 7465150 modifies s1 when it shouldn't.  EXPECT_EQ(s1.size(), size);  EXPECT_EQ(s2.size(), size + 1);}TEST(MakeFragmentedCord, MakeFragmentedCordFromInitializerList) {  absl::Cord fragmented =      absl::MakeFragmentedCord({"A ", "fragmented ", "Cord"});  EXPECT_EQ("A fragmented Cord", fragmented);  auto chunk_it = fragmented.chunk_begin();  ASSERT_TRUE(chunk_it != fragmented.chunk_end());  EXPECT_EQ("A ", *chunk_it);  ASSERT_TRUE(++chunk_it != fragmented.chunk_end());  EXPECT_EQ("fragmented ", *chunk_it);  ASSERT_TRUE(++chunk_it != fragmented.chunk_end());  EXPECT_EQ("Cord", *chunk_it);  ASSERT_TRUE(++chunk_it == fragmented.chunk_end());}TEST(MakeFragmentedCord, MakeFragmentedCordFromVector) {  std::vector<absl::string_view> chunks = {"A ", "fragmented ", "Cord"};  absl::Cord fragmented = absl::MakeFragmentedCord(chunks);  EXPECT_EQ("A fragmented Cord", fragmented);  auto chunk_it = fragmented.chunk_begin();  ASSERT_TRUE(chunk_it != fragmented.chunk_end());  EXPECT_EQ("A ", *chunk_it);  ASSERT_TRUE(++chunk_it != fragmented.chunk_end());  EXPECT_EQ("fragmented ", *chunk_it);  ASSERT_TRUE(++chunk_it != fragmented.chunk_end());  EXPECT_EQ("Cord", *chunk_it);  ASSERT_TRUE(++chunk_it == fragmented.chunk_end());}TEST(CordChunkIterator, Traits) {  static_assert(std::is_copy_constructible<absl::Cord::ChunkIterator>::value,                "");  static_assert(std::is_copy_assignable<absl::Cord::ChunkIterator>::value, "");  // Move semantics to satisfy swappable via std::swap  static_assert(std::is_move_constructible<absl::Cord::ChunkIterator>::value,                "");  static_assert(std::is_move_assignable<absl::Cord::ChunkIterator>::value, "");  static_assert(      std::is_same<          std::iterator_traits<absl::Cord::ChunkIterator>::iterator_category,          std::input_iterator_tag>::value,      "");  static_assert(      std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::value_type,                   absl::string_view>::value,      "");  static_assert(      std::is_same<          std::iterator_traits<absl::Cord::ChunkIterator>::difference_type,          ptrdiff_t>::value,      "");  static_assert(      std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::pointer,                   const absl::string_view*>::value,      "");  static_assert(      std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::reference,                   absl::string_view>::value,      "");}static void VerifyChunkIterator(const absl::Cord& cord,                                size_t expected_chunks) {  EXPECT_EQ(cord.chunk_begin() == cord.chunk_end(), cord.empty()) << cord;  EXPECT_EQ(cord.chunk_begin() != cord.chunk_end(), !cord.empty());  absl::Cord::ChunkRange range = cord.Chunks();  EXPECT_EQ(range.begin() == range.end(), cord.empty());  EXPECT_EQ(range.begin() != range.end(), !cord.empty());  std::string content(cord);  size_t pos = 0;  auto pre_iter = cord.chunk_begin(), post_iter = cord.chunk_begin();  size_t n_chunks = 0;  while (pre_iter != cord.chunk_end() && post_iter != cord.chunk_end()) {    EXPECT_FALSE(pre_iter == cord.chunk_end());   // NOLINT: explicitly test ==    EXPECT_FALSE(post_iter == cord.chunk_end());  // NOLINT    EXPECT_EQ(pre_iter, post_iter);    EXPECT_EQ(*pre_iter, *post_iter);    EXPECT_EQ(pre_iter->data(), (*pre_iter).data());    EXPECT_EQ(pre_iter->size(), (*pre_iter).size());    absl::string_view chunk = *pre_iter;    EXPECT_FALSE(chunk.empty());    EXPECT_LE(pos + chunk.size(), content.size());    EXPECT_EQ(absl::string_view(content.c_str() + pos, chunk.size()), chunk);    int n_equal_iterators = 0;    for (absl::Cord::ChunkIterator it = range.begin(); it != range.end();         ++it) {      n_equal_iterators += static_cast<int>(it == pre_iter);    }    EXPECT_EQ(n_equal_iterators, 1);    ++pre_iter;    EXPECT_EQ(*post_iter++, chunk);    pos += chunk.size();    ++n_chunks;  }  EXPECT_EQ(expected_chunks, n_chunks);  EXPECT_EQ(pos, content.size());  EXPECT_TRUE(pre_iter == cord.chunk_end());   // NOLINT: explicitly test ==  EXPECT_TRUE(post_iter == cord.chunk_end());  // NOLINT}TEST(CordChunkIterator, Operations) {  absl::Cord empty_cord;  VerifyChunkIterator(empty_cord, 0);  absl::Cord small_buffer_cord("small cord");  VerifyChunkIterator(small_buffer_cord, 1);  absl::Cord flat_node_cord("larger than small buffer optimization");  VerifyChunkIterator(flat_node_cord, 1);  VerifyChunkIterator(      absl::MakeFragmentedCord({"a ", "small ", "fragmented ", "cord ", "for ",                                "testing ", "chunk ", "iterations."}),      8);  absl::Cord reused_nodes_cord(std::string(40, 'c'));  reused_nodes_cord.Prepend(absl::Cord(std::string(40, 'b')));  reused_nodes_cord.Prepend(absl::Cord(std::string(40, 'a')));  size_t expected_chunks = 3;  for (int i = 0; i < 8; ++i) {    reused_nodes_cord.Prepend(reused_nodes_cord);    expected_chunks *= 2;    VerifyChunkIterator(reused_nodes_cord, expected_chunks);  }  RandomEngine rng(testing::GTEST_FLAG(random_seed));  absl::Cord flat_cord(RandomLowercaseString(&rng, 256));  absl::Cord subcords;  for (int i = 0; i < 128; ++i) subcords.Prepend(flat_cord.Subcord(i, 128));  VerifyChunkIterator(subcords, 128);}TEST(CordCharIterator, Traits) {  static_assert(std::is_copy_constructible<absl::Cord::CharIterator>::value,                "");  static_assert(std::is_copy_assignable<absl::Cord::CharIterator>::value, "");  // Move semantics to satisfy swappable via std::swap  static_assert(std::is_move_constructible<absl::Cord::CharIterator>::value,                "");  static_assert(std::is_move_assignable<absl::Cord::CharIterator>::value, "");  static_assert(      std::is_same<          std::iterator_traits<absl::Cord::CharIterator>::iterator_category,          std::input_iterator_tag>::value,      "");  static_assert(      std::is_same<std::iterator_traits<absl::Cord::CharIterator>::value_type,                   char>::value,      "");  static_assert(      std::is_same<          std::iterator_traits<absl::Cord::CharIterator>::difference_type,          ptrdiff_t>::value,      "");  static_assert(      std::is_same<std::iterator_traits<absl::Cord::CharIterator>::pointer,                   const char*>::value,      "");  static_assert(      std::is_same<std::iterator_traits<absl::Cord::CharIterator>::reference,                   const char&>::value,      "");}static void VerifyCharIterator(const absl::Cord& cord) {  EXPECT_EQ(cord.char_begin() == cord.char_end(), cord.empty());  EXPECT_EQ(cord.char_begin() != cord.char_end(), !cord.empty());  absl::Cord::CharRange range = cord.Chars();  EXPECT_EQ(range.begin() == range.end(), cord.empty());  EXPECT_EQ(range.begin() != range.end(), !cord.empty());  size_t i = 0;  absl::Cord::CharIterator pre_iter = cord.char_begin();  absl::Cord::CharIterator post_iter = cord.char_begin();  std::string content(cord);  while (pre_iter != cord.char_end() && post_iter != cord.char_end()) {    EXPECT_FALSE(pre_iter == cord.char_end());   // NOLINT: explicitly test ==    EXPECT_FALSE(post_iter == cord.char_end());  // NOLINT    EXPECT_LT(i, cord.size());    EXPECT_EQ(content[i], *pre_iter);    EXPECT_EQ(pre_iter, post_iter);    EXPECT_EQ(*pre_iter, *post_iter);    EXPECT_EQ(&*pre_iter, &*post_iter);    EXPECT_EQ(&*pre_iter, pre_iter.operator->());    const char* character_address = &*pre_iter;    absl::Cord::CharIterator copy = pre_iter;    ++copy;    EXPECT_EQ(character_address, &*pre_iter);    int n_equal_iterators = 0;    for (absl::Cord::CharIterator it = range.begin(); it != range.end(); ++it) {      n_equal_iterators += static_cast<int>(it == pre_iter);    }    EXPECT_EQ(n_equal_iterators, 1);    absl::Cord::CharIterator advance_iter = range.begin();    absl::Cord::Advance(&advance_iter, i);    EXPECT_EQ(pre_iter, advance_iter);    advance_iter = range.begin();    EXPECT_EQ(absl::Cord::AdvanceAndRead(&advance_iter, i), cord.Subcord(0, i));    EXPECT_EQ(pre_iter, advance_iter);    advance_iter = pre_iter;    absl::Cord::Advance(&advance_iter, cord.size() - i);    EXPECT_EQ(range.end(), advance_iter);    advance_iter = pre_iter;    EXPECT_EQ(absl::Cord::AdvanceAndRead(&advance_iter, cord.size() - i),              cord.Subcord(i, cord.size() - i));    EXPECT_EQ(range.end(), advance_iter);    ++i;    ++pre_iter;    post_iter++;  }  EXPECT_EQ(i, cord.size());  EXPECT_TRUE(pre_iter == cord.char_end());   // NOLINT: explicitly test ==  EXPECT_TRUE(post_iter == cord.char_end());  // NOLINT  absl::Cord::CharIterator zero_advanced_end = cord.char_end();  absl::Cord::Advance(&zero_advanced_end, 0);  EXPECT_EQ(zero_advanced_end, cord.char_end());  absl::Cord::CharIterator it = cord.char_begin();  for (absl::string_view chunk : cord.Chunks()) {    while (!chunk.empty()) {      EXPECT_EQ(absl::Cord::ChunkRemaining(it), chunk);      chunk.remove_prefix(1);      ++it;    }  }}TEST(CordCharIterator, Operations) {  absl::Cord empty_cord;  VerifyCharIterator(empty_cord);  absl::Cord small_buffer_cord("small cord");  VerifyCharIterator(small_buffer_cord);  absl::Cord flat_node_cord("larger than small buffer optimization");  VerifyCharIterator(flat_node_cord);  VerifyCharIterator(      absl::MakeFragmentedCord({"a ", "small ", "fragmented ", "cord ", "for ",                                "testing ", "character ", "iteration."}));  absl::Cord reused_nodes_cord("ghi");  reused_nodes_cord.Prepend(absl::Cord("def"));  reused_nodes_cord.Prepend(absl::Cord("abc"));  for (int i = 0; i < 4; ++i) {    reused_nodes_cord.Prepend(reused_nodes_cord);    VerifyCharIterator(reused_nodes_cord);  }  RandomEngine rng(testing::GTEST_FLAG(random_seed));  absl::Cord flat_cord(RandomLowercaseString(&rng, 256));  absl::Cord subcords;  for (int i = 0; i < 4; ++i) subcords.Prepend(flat_cord.Subcord(16 * i, 128));  VerifyCharIterator(subcords);}TEST(Cord, StreamingOutput) {  absl::Cord c =      absl::MakeFragmentedCord({"A ", "small ", "fragmented ", "Cord", "."});  std::stringstream output;  output << c;  EXPECT_EQ("A small fragmented Cord.", output.str());}TEST(Cord, ForEachChunk) {  for (int num_elements : {1, 10, 200}) {    SCOPED_TRACE(num_elements);    std::vector<std::string> cord_chunks;    for (int i = 0; i < num_elements; ++i) {      cord_chunks.push_back(absl::StrCat("[", i, "]"));    }    absl::Cord c = absl::MakeFragmentedCord(cord_chunks);    std::vector<std::string> iterated_chunks;    absl::CordTestPeer::ForEachChunk(c,                                     [&iterated_chunks](absl::string_view sv) {                                       iterated_chunks.emplace_back(sv);                                     });    EXPECT_EQ(iterated_chunks, cord_chunks);  }}TEST(Cord, SmallBufferAssignFromOwnData) {  constexpr size_t kMaxInline = 15;  std::string contents = "small buff cord";  EXPECT_EQ(contents.size(), kMaxInline);  for (size_t pos = 0; pos < contents.size(); ++pos) {    for (size_t count = contents.size() - pos; count > 0; --count) {      absl::Cord c(contents);      absl::string_view flat = c.Flatten();      c = flat.substr(pos, count);      EXPECT_EQ(c, contents.substr(pos, count))          << "pos = " << pos << "; count = " << count;    }  }}
 |