cord_rep_btree_test.cc
Go to the documentation of this file.
1 // Copyright 2021 The Abseil Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
17 #include <cmath>
18 #include <deque>
19 #include <iostream>
20 #include <string>
21 #include <vector>
22 
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "absl/base/config.h"
26 #include "absl/base/internal/raw_logging.h"
27 #include "absl/cleanup/cleanup.h"
29 #include "absl/strings/internal/cord_internal.h"
31 #include "absl/strings/str_cat.h"
32 #include "absl/strings/string_view.h"
33 
34 namespace absl {
36 namespace cord_internal {
37 
39  public:
40  static void SetEdge(CordRepBtree* node, size_t idx, CordRep* edge) {
41  node->edges_[idx] = edge;
42  }
43  static void AddEdge(CordRepBtree* node, CordRep* edge) {
44  node->edges_[node->fetch_add_end(1)] = edge;
45  }
46 };
47 
48 namespace {
49 
50 using ::absl::cordrep_testing::AutoUnref;
62 using ::testing::Conditional;
72 
73 MATCHER_P(EqFlatHolding, data, "Equals flat holding data") {
74  if (arg->tag < FLAT) {
75  *result_listener << "Expected FLAT, got tag " << static_cast<int>(arg->tag);
76  return false;
77  }
78  std::string actual = CordToString(arg);
79  if (actual != data) {
80  *result_listener << "Expected flat holding \"" << data
81  << "\", got flat holding \"" << actual << "\"";
82  return false;
83  }
84  return true;
85 }
86 
87 MATCHER_P(IsNode, height, absl::StrCat("Is a valid node of height ", height)) {
88  if (arg == nullptr) {
89  *result_listener << "Expected NODE, got nullptr";
90  return false;
91  }
92  if (arg->tag != BTREE) {
93  *result_listener << "Expected NODE, got " << static_cast<int>(arg->tag);
94  return false;
95  }
96  if (!CordRepBtree::IsValid(arg->btree())) {
97  CordRepBtree::Dump(arg->btree(), "Expected valid NODE, got:", false,
98  *result_listener->stream());
99  return false;
100  }
101  if (arg->btree()->height() != height) {
102  *result_listener << "Expected NODE of height " << height << ", got "
103  << arg->btree()->height();
104  return false;
105  }
106  return true;
107 }
108 
110  absl::StrCat("Is a substring(start = ", start, ", length = ", length,
111  ")")) {
112  if (arg == nullptr) {
113  *result_listener << "Expected substring, got nullptr";
114  return false;
115  }
116  if (arg->tag != SUBSTRING) {
117  *result_listener << "Expected SUBSTRING, got "
118  << static_cast<int>(arg->tag);
119  return false;
120  }
121  const CordRepSubstring* const substr = arg->substring();
122  if (substr->start != start || substr->length != length) {
123  *result_listener << "Expected substring(" << start << ", " << length
124  << "), got substring(" << substr->start << ", "
125  << substr->length << ")";
126  return false;
127  }
128  return true;
129 }
130 
131 MATCHER_P2(EqExtractResult, tree, rep, "Equals ExtractResult") {
132  if (arg.tree != tree || arg.extracted != rep) {
133  *result_listener << "Expected {" << static_cast<const void*>(tree) << ", "
134  << static_cast<const void*>(rep) << "}, got {" << arg.tree
135  << ", " << arg.extracted << "}";
136  return false;
137  }
138  return true;
139 }
140 
141 // DataConsumer is a simple helper class used by tests to 'consume' string
142 // fragments from the provided input in forward or backward direction.
143 class DataConsumer {
144  public:
145  // Starts consumption of `data`. Caller must make sure `data` outlives this
146  // instance. Consumes data starting at the front if `forward` is true, else
147  // consumes data from the back.
148  DataConsumer(absl::string_view data, bool forward)
149  : data_(data), forward_(forward) {}
150 
151  // Return the next `n` bytes from referenced data.
152  absl::string_view Next(size_t n) {
153  assert(n <= data_.size() - consumed_);
154  consumed_ += n;
155  return data_.substr(forward_ ? consumed_ - n : data_.size() - consumed_, n);
156  }
157 
158  // Returns all data consumed so far.
159  absl::string_view Consumed() const {
160  return forward_ ? data_.substr(0, consumed_)
162  }
163 
164  private:
166  size_t consumed_ = 0;
167  bool forward_;
168 };
169 
170 // BtreeAdd returns either CordRepBtree::Append or CordRepBtree::Prepend.
171 CordRepBtree* BtreeAdd(CordRepBtree* node, bool append,
173  return append ? CordRepBtree::Append(node, data)
174  : CordRepBtree::Prepend(node, data);
175 }
176 
177 // Recursively collects all leaf edges from `tree` and appends them to `edges`.
178 void GetLeafEdges(const CordRepBtree* tree, std::vector<CordRep*>& edges) {
179  if (tree->height() == 0) {
180  for (CordRep* edge : tree->Edges()) {
181  edges.push_back(edge);
182  }
183  } else {
184  for (CordRep* edge : tree->Edges()) {
185  GetLeafEdges(edge->btree(), edges);
186  }
187  }
188 }
189 
190 // Recursively collects and returns all leaf edges from `tree`.
191 std::vector<CordRep*> GetLeafEdges(const CordRepBtree* tree) {
192  std::vector<CordRep*> edges;
193  GetLeafEdges(tree, edges);
194  return edges;
195 }
196 
197 // Creates a flat containing the hexadecimal value of `i` zero padded
198 // to at least 4 digits prefixed with "0x", e.g.: "0x04AC".
199 CordRepFlat* MakeHexFlat(size_t i) {
200  return MakeFlat(absl::StrCat("0x", absl::Hex(i, absl::kZeroPad4)));
201 }
202 
203 CordRepBtree* MakeLeaf(size_t size = CordRepBtree::kMaxCapacity) {
204  assert(size <= CordRepBtree::kMaxCapacity);
205  CordRepBtree* leaf = CordRepBtree::Create(MakeHexFlat(0));
206  for (size_t i = 1; i < size; ++i) {
207  leaf = CordRepBtree::Append(leaf, MakeHexFlat(i));
208  }
209  return leaf;
210 }
211 
212 CordRepBtree* MakeTree(size_t size, bool append = true) {
213  CordRepBtree* tree = CordRepBtree::Create(MakeHexFlat(0));
214  for (size_t i = 1; i < size; ++i) {
215  tree = append ? CordRepBtree::Append(tree, MakeHexFlat(i))
216  : CordRepBtree::Prepend(tree, MakeHexFlat(i));
217  }
218  return tree;
219 }
220 
221 CordRepBtree* CreateTree(absl::Span<CordRep* const> reps) {
222  auto it = reps.begin();
223  CordRepBtree* tree = CordRepBtree::Create(*it);
224  while (++it != reps.end()) tree = CordRepBtree::Append(tree, *it);
225  return tree;
226 }
227 
228 CordRepBtree* CreateTree(absl::string_view data, size_t chunk_size) {
229  return CreateTree(CreateFlatsFromString(data, chunk_size));
230 }
231 
232 CordRepBtree* CreateTreeReverse(absl::string_view data, size_t chunk_size) {
233  std::vector<CordRep*> flats = CreateFlatsFromString(data, chunk_size);
234  auto rit = flats.rbegin();
235  CordRepBtree* tree = CordRepBtree::Create(*rit);
236  while (++rit != flats.rend()) tree = CordRepBtree::Prepend(tree, *rit);
237  return tree;
238 }
239 
240 class CordRepBtreeTest : public testing::TestWithParam<bool> {
241  public:
242  bool shared() const { return GetParam(); }
243 
245  return param.param ? "Shared" : "Private";
246  }
247 };
248 
249 INSTANTIATE_TEST_SUITE_P(WithParam, CordRepBtreeTest, testing::Bool(),
251 
252 class CordRepBtreeHeightTest : public testing::TestWithParam<int> {
253  public:
254  int height() const { return GetParam(); }
255 
257  return absl::StrCat(param.param);
258  }
259 };
260 
261 INSTANTIATE_TEST_SUITE_P(WithHeights, CordRepBtreeHeightTest,
264 
265 using TwoBools = testing::tuple<bool, bool>;
266 
267 class CordRepBtreeDualTest : public testing::TestWithParam<TwoBools> {
268  public:
269  bool first_shared() const { return std::get<0>(GetParam()); }
270  bool second_shared() const { return std::get<1>(GetParam()); }
271 
273  if (std::get<0>(param.param)) {
274  return std::get<1>(param.param) ? "BothShared" : "FirstShared";
275  }
276  return std::get<1>(param.param) ? "SecondShared" : "Private";
277  }
278 };
279 
280 INSTANTIATE_TEST_SUITE_P(WithParam, CordRepBtreeDualTest,
283 
284 TEST(CordRepBtreeTest, SizeIsMultipleOf64) {
285  // Only enforce for fully 64-bit platforms.
286  if (sizeof(size_t) == 8 && sizeof(void*) == 8) {
287  EXPECT_THAT(sizeof(CordRepBtree) % 64, Eq(0)) << "Should be multiple of 64";
288  }
289 }
290 
291 TEST(CordRepBtreeTest, NewDestroyEmptyTree) {
292  auto* tree = CordRepBtree::New();
293  EXPECT_THAT(tree->size(), Eq(0));
294  EXPECT_THAT(tree->height(), Eq(0));
295  EXPECT_THAT(tree->Edges(), ElementsAre());
296  CordRepBtree::Destroy(tree);
297 }
298 
299 TEST(CordRepBtreeTest, NewDestroyEmptyTreeAtHeight) {
300  auto* tree = CordRepBtree::New(3);
301  EXPECT_THAT(tree->size(), Eq(0));
302  EXPECT_THAT(tree->height(), Eq(3));
303  EXPECT_THAT(tree->Edges(), ElementsAre());
304  CordRepBtree::Destroy(tree);
305 }
306 
307 TEST(CordRepBtreeTest, Btree) {
308  CordRep* rep = CordRepBtree::New();
309  EXPECT_THAT(rep->btree(), Eq(rep));
310  EXPECT_THAT(static_cast<const CordRep*>(rep)->btree(), Eq(rep));
312 #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
313  rep = MakeFlat("Hello world");
314  EXPECT_DEATH(rep->btree(), ".*");
315  EXPECT_DEATH(static_cast<const CordRep*>(rep)->btree(), ".*");
317 #endif
318 }
319 
320 TEST(CordRepBtreeTest, EdgeData) {
321  CordRepFlat* flat = MakeFlat("Hello world");
322  CordRepExternal* external = MakeExternal("Hello external");
323  CordRep* substr1 = MakeSubstring(1, 6, CordRep::Ref(flat));
324  CordRep* substr2 = MakeSubstring(1, 6, CordRep::Ref(external));
325  CordRep* bad_substr = MakeSubstring(1, 2, CordRep::Ref(substr1));
326 
327  EXPECT_TRUE(IsDataEdge(flat));
328  EXPECT_THAT(EdgeData(flat).data(), TypedEq<const void*>(flat->Data()));
329  EXPECT_THAT(EdgeData(flat), Eq("Hello world"));
330 
331  EXPECT_TRUE(IsDataEdge(external));
332  EXPECT_THAT(EdgeData(external).data(), TypedEq<const void*>(external->base));
333  EXPECT_THAT(EdgeData(external), Eq("Hello external"));
334 
335  EXPECT_TRUE(IsDataEdge(substr1));
336  EXPECT_THAT(EdgeData(substr1).data(), TypedEq<const void*>(flat->Data() + 1));
337  EXPECT_THAT(EdgeData(substr1), Eq("ello w"));
338 
339  EXPECT_TRUE(IsDataEdge(substr2));
340  EXPECT_THAT(EdgeData(substr2).data(),
341  TypedEq<const void*>(external->base + 1));
342  EXPECT_THAT(EdgeData(substr2), Eq("ello e"));
343 
344  EXPECT_FALSE(IsDataEdge(bad_substr));
345 #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
346  EXPECT_DEATH(EdgeData(bad_substr), ".*");
347 #endif
348 
349  CordRep::Unref(bad_substr);
350  CordRep::Unref(substr2);
351  CordRep::Unref(substr1);
352  CordRep::Unref(external);
353  CordRep::Unref(flat);
354 }
355 
356 TEST(CordRepBtreeTest, CreateUnrefLeaf) {
357  auto* flat = MakeFlat("a");
358  auto* leaf = CordRepBtree::Create(flat);
359  EXPECT_THAT(leaf->size(), Eq(1));
360  EXPECT_THAT(leaf->height(), Eq(0));
361  EXPECT_THAT(leaf->Edges(), ElementsAre(flat));
362  CordRepBtree::Unref(leaf);
363 }
364 
365 TEST(CordRepBtreeTest, NewUnrefNode) {
366  auto* leaf = CordRepBtree::Create(MakeFlat("a"));
367  CordRepBtree* tree = CordRepBtree::New(leaf);
368  EXPECT_THAT(tree->size(), Eq(1));
369  EXPECT_THAT(tree->height(), Eq(1));
370  EXPECT_THAT(tree->Edges(), ElementsAre(leaf));
371  CordRepBtree::Unref(tree);
372 }
373 
374 TEST_P(CordRepBtreeTest, AppendToLeafToCapacity) {
375  AutoUnref refs;
376  std::vector<CordRep*> flats;
377  flats.push_back(MakeHexFlat(0));
378  auto* leaf = CordRepBtree::Create(flats.back());
379 
380  for (size_t i = 1; i < CordRepBtree::kMaxCapacity; ++i) {
381  refs.RefIf(shared(), leaf);
382  flats.push_back(MakeHexFlat(i));
383  auto* result = CordRepBtree::Append(leaf, flats.back());
384  EXPECT_THAT(result->height(), Eq(0));
385  EXPECT_THAT(result, Conditional(shared(), Ne(leaf), Eq(leaf)));
386  EXPECT_THAT(result->Edges(), ElementsAreArray(flats));
387  leaf = result;
388  }
389  CordRep::Unref(leaf);
390 }
391 
392 TEST_P(CordRepBtreeTest, PrependToLeafToCapacity) {
393  AutoUnref refs;
394  std::deque<CordRep*> flats;
395  flats.push_front(MakeHexFlat(0));
396  auto* leaf = CordRepBtree::Create(flats.front());
397 
398  for (size_t i = 1; i < CordRepBtree::kMaxCapacity; ++i) {
399  refs.RefIf(shared(), leaf);
400  flats.push_front(MakeHexFlat(i));
401  auto* result = CordRepBtree::Prepend(leaf, flats.front());
402  EXPECT_THAT(result->height(), Eq(0));
403  EXPECT_THAT(result, Conditional(shared(), Ne(leaf), Eq(leaf)));
404  EXPECT_THAT(result->Edges(), ElementsAreArray(flats));
405  leaf = result;
406  }
407  CordRep::Unref(leaf);
408 }
409 
410 // This test specifically aims at code aligning data at either the front or the
411 // back of the contained `edges[]` array, alternating Append and Prepend will
412 // move `begin()` and `end()` values as needed for each added value.
413 TEST_P(CordRepBtreeTest, AppendPrependToLeafToCapacity) {
414  AutoUnref refs;
415  std::deque<CordRep*> flats;
416  flats.push_front(MakeHexFlat(0));
417  auto* leaf = CordRepBtree::Create(flats.front());
418 
419  for (size_t i = 1; i < CordRepBtree::kMaxCapacity; ++i) {
420  refs.RefIf(shared(), leaf);
421  CordRepBtree* result;
422  if (i % 2 != 0) {
423  flats.push_front(MakeHexFlat(i));
424  result = CordRepBtree::Prepend(leaf, flats.front());
425  } else {
426  flats.push_back(MakeHexFlat(i));
427  result = CordRepBtree::Append(leaf, flats.back());
428  }
429  EXPECT_THAT(result->height(), Eq(0));
430  EXPECT_THAT(result, Conditional(shared(), Ne(leaf), Eq(leaf)));
431  EXPECT_THAT(result->Edges(), ElementsAreArray(flats));
432  leaf = result;
433  }
434  CordRep::Unref(leaf);
435 }
436 
437 TEST_P(CordRepBtreeTest, AppendToLeafBeyondCapacity) {
438  AutoUnref refs;
439  auto* leaf = MakeLeaf();
440  refs.RefIf(shared(), leaf);
441  CordRep* flat = MakeFlat("abc");
442  auto* result = CordRepBtree::Append(leaf, flat);
443  ASSERT_THAT(result, IsNode(1));
444  EXPECT_THAT(result, Ne(leaf));
445  absl::Span<CordRep* const> edges = result->Edges();
446  ASSERT_THAT(edges, ElementsAre(leaf, IsNode(0)));
447  EXPECT_THAT(edges[1]->btree()->Edges(), ElementsAre(flat));
449 }
450 
451 TEST_P(CordRepBtreeTest, PrependToLeafBeyondCapacity) {
452  AutoUnref refs;
453  auto* leaf = MakeLeaf();
454  refs.RefIf(shared(), leaf);
455  CordRep* flat = MakeFlat("abc");
456  auto* result = CordRepBtree::Prepend(leaf, flat);
457  ASSERT_THAT(result, IsNode(1));
458  EXPECT_THAT(result, Ne(leaf));
459  absl::Span<CordRep* const> edges = result->Edges();
460  ASSERT_THAT(edges, ElementsAre(IsNode(0), leaf));
461  EXPECT_THAT(edges[0]->btree()->Edges(), ElementsAre(flat));
463 }
464 
465 TEST_P(CordRepBtreeTest, AppendToTreeOneDeep) {
466  constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
467  AutoUnref refs;
468  std::vector<CordRep*> flats;
469  flats.push_back(MakeHexFlat(0));
470  CordRepBtree* tree = CordRepBtree::Create(flats.back());
471  for (size_t i = 1; i <= max_cap; ++i) {
472  flats.push_back(MakeHexFlat(i));
473  tree = CordRepBtree::Append(tree, flats.back());
474  }
475  ASSERT_THAT(tree, IsNode(1));
476 
477  for (size_t i = max_cap + 1; i < max_cap * max_cap; ++i) {
478  // Ref top level tree based on param.
479  // Ref leaf node once every 4 iterations, which should not have an
480  // observable effect other than that the leaf itself is copied.
481  refs.RefIf(shared(), tree);
482  refs.RefIf(i % 4 == 0, tree->Edges().back());
483 
484  flats.push_back(MakeHexFlat(i));
485  CordRepBtree* result = CordRepBtree::Append(tree, flats.back());
486  ASSERT_THAT(result, IsNode(1));
487  ASSERT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
488  std::vector<CordRep*> edges = GetLeafEdges(result);
489  ASSERT_THAT(edges, ElementsAreArray(flats));
490  tree = result;
491  }
492  CordRep::Unref(tree);
493 }
494 
495 TEST_P(CordRepBtreeTest, AppendToTreeTwoDeep) {
496  constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
497  AutoUnref refs;
498  std::vector<CordRep*> flats;
499  flats.push_back(MakeHexFlat(0));
500  CordRepBtree* tree = CordRepBtree::Create(flats.back());
501  for (size_t i = 1; i <= max_cap * max_cap; ++i) {
502  flats.push_back(MakeHexFlat(i));
503  tree = CordRepBtree::Append(tree, flats.back());
504  }
505  ASSERT_THAT(tree, IsNode(2));
506  for (size_t i = max_cap * max_cap + 1; i < max_cap * max_cap * max_cap; ++i) {
507  // Ref top level tree based on param.
508  // Ref child node once every 16 iterations, and leaf node every 4
509  // iterrations which which should not have an observable effect other than
510  // the node and/or the leaf below it being copied.
511  refs.RefIf(shared(), tree);
512  refs.RefIf(i % 16 == 0, tree->Edges().back());
513  refs.RefIf(i % 4 == 0, tree->Edges().back()->btree()->Edges().back());
514 
515  flats.push_back(MakeHexFlat(i));
516  CordRepBtree* result = CordRepBtree::Append(tree, flats.back());
517  ASSERT_THAT(result, IsNode(2));
518  ASSERT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
519  std::vector<CordRep*> edges = GetLeafEdges(result);
520  ASSERT_THAT(edges, ElementsAreArray(flats));
521  tree = result;
522  }
523  CordRep::Unref(tree);
524 }
525 
526 TEST_P(CordRepBtreeTest, PrependToTreeOneDeep) {
527  constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
528  AutoUnref refs;
529  std::deque<CordRep*> flats;
530  flats.push_back(MakeHexFlat(0));
531  CordRepBtree* tree = CordRepBtree::Create(flats.back());
532  for (size_t i = 1; i <= max_cap; ++i) {
533  flats.push_front(MakeHexFlat(i));
534  tree = CordRepBtree::Prepend(tree, flats.front());
535  }
536  ASSERT_THAT(tree, IsNode(1));
537 
538  for (size_t i = max_cap + 1; i < max_cap * max_cap; ++i) {
539  // Ref top level tree based on param.
540  // Ref leaf node once every 4 iterations which should not have an observable
541  // effect other than than the leaf itself is copied.
542  refs.RefIf(shared(), tree);
543  refs.RefIf(i % 4 == 0, tree->Edges().back());
544 
545  flats.push_front(MakeHexFlat(i));
546  CordRepBtree* result = CordRepBtree::Prepend(tree, flats.front());
547  ASSERT_THAT(result, IsNode(1));
548  ASSERT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
549  std::vector<CordRep*> edges = GetLeafEdges(result);
550  ASSERT_THAT(edges, ElementsAreArray(flats));
551  tree = result;
552  }
553  CordRep::Unref(tree);
554 }
555 
556 TEST_P(CordRepBtreeTest, PrependToTreeTwoDeep) {
557  constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
558  AutoUnref refs;
559  std::deque<CordRep*> flats;
560  flats.push_back(MakeHexFlat(0));
561  CordRepBtree* tree = CordRepBtree::Create(flats.back());
562  for (size_t i = 1; i <= max_cap * max_cap; ++i) {
563  flats.push_front(MakeHexFlat(i));
564  tree = CordRepBtree::Prepend(tree, flats.front());
565  }
566  ASSERT_THAT(tree, IsNode(2));
567  for (size_t i = max_cap * max_cap + 1; i < max_cap * max_cap * max_cap; ++i) {
568  // Ref top level tree based on param.
569  // Ref child node once every 16 iterations, and leaf node every 4
570  // iterrations which which should not have an observable effect other than
571  // the node and/or the leaf below it being copied.
572  refs.RefIf(shared(), tree);
573  refs.RefIf(i % 16 == 0, tree->Edges().back());
574  refs.RefIf(i % 4 == 0, tree->Edges().back()->btree()->Edges().back());
575 
576  flats.push_front(MakeHexFlat(i));
577  CordRepBtree* result = CordRepBtree::Prepend(tree, flats.front());
578  ASSERT_THAT(result, IsNode(2));
579  ASSERT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
580  std::vector<CordRep*> edges = GetLeafEdges(result);
581  ASSERT_THAT(edges, ElementsAreArray(flats));
582  tree = result;
583  }
584  CordRep::Unref(tree);
585 }
586 
587 TEST_P(CordRepBtreeDualTest, MergeLeafsNotExceedingCapacity) {
588  for (bool use_append : {false, true}) {
589  SCOPED_TRACE(use_append ? "Using Append" : "Using Prepend");
590 
591  AutoUnref refs;
592  std::vector<CordRep*> flats;
593 
594  // Build `left` side leaf appending all contained flats to `flats`
595  CordRepBtree* left = MakeLeaf(3);
596  GetLeafEdges(left, flats);
597  refs.RefIf(first_shared(), left);
598 
599  // Build `right` side leaf appending all contained flats to `flats`
600  CordRepBtree* right = MakeLeaf(2);
601  GetLeafEdges(right, flats);
602  refs.RefIf(second_shared(), right);
603 
604  CordRepBtree* tree = use_append ? CordRepBtree::Append(left, right)
605  : CordRepBtree::Prepend(right, left);
606  EXPECT_THAT(tree, IsNode(0));
607 
608  // `tree` contains all flats originally belonging to `left` and `right`.
609  EXPECT_THAT(tree->Edges(), ElementsAreArray(flats));
610  CordRepBtree::Unref(tree);
611  }
612 }
613 
614 TEST_P(CordRepBtreeDualTest, MergeLeafsExceedingCapacity) {
615  for (bool use_append : {false, true}) {
616  SCOPED_TRACE(use_append ? "Using Append" : "Using Prepend");
617 
618  AutoUnref refs;
619 
620  // Build `left` side tree appending all contained flats to `flats`
621  CordRepBtree* left = MakeLeaf(CordRepBtree::kMaxCapacity - 2);
622  refs.RefIf(first_shared(), left);
623 
624  // Build `right` side tree appending all contained flats to `flats`
625  CordRepBtree* right = MakeLeaf(CordRepBtree::kMaxCapacity - 1);
626  refs.RefIf(second_shared(), right);
627 
628  CordRepBtree* tree = use_append ? CordRepBtree::Append(left, right)
629  : CordRepBtree::Prepend(right, left);
630  EXPECT_THAT(tree, IsNode(1));
631  EXPECT_THAT(tree->Edges(), ElementsAre(left, right));
632  CordRepBtree::Unref(tree);
633  }
634 }
635 
636 TEST_P(CordRepBtreeDualTest, MergeEqualHeightTrees) {
637  for (bool use_append : {false, true}) {
638  SCOPED_TRACE(use_append ? "Using Append" : "Using Prepend");
639 
640  AutoUnref refs;
641  std::vector<CordRep*> flats;
642 
643  // Build `left` side tree appending all contained flats to `flats`
644  CordRepBtree* left = MakeTree(CordRepBtree::kMaxCapacity * 3);
645  GetLeafEdges(left, flats);
646  refs.RefIf(first_shared(), left);
647 
648  // Build `right` side tree appending all contained flats to `flats`
649  CordRepBtree* right = MakeTree(CordRepBtree::kMaxCapacity * 2);
650  GetLeafEdges(right, flats);
651  refs.RefIf(second_shared(), right);
652 
653  CordRepBtree* tree = use_append ? CordRepBtree::Append(left, right)
654  : CordRepBtree::Prepend(right, left);
655  EXPECT_THAT(tree, IsNode(1));
656  EXPECT_THAT(tree->Edges(), SizeIs(5));
657 
658  // `tree` contains all flats originally belonging to `left` and `right`.
659  EXPECT_THAT(GetLeafEdges(tree), ElementsAreArray(flats));
660  CordRepBtree::Unref(tree);
661  }
662 }
663 
664 TEST_P(CordRepBtreeDualTest, MergeLeafWithTreeNotExceedingLeafCapacity) {
665  for (bool use_append : {false, true}) {
666  SCOPED_TRACE(use_append ? "Using Append" : "Using Prepend");
667 
668  AutoUnref refs;
669  std::vector<CordRep*> flats;
670 
671  // Build `left` side tree appending all added flats to `flats`
672  CordRepBtree* left = MakeTree(CordRepBtree::kMaxCapacity * 2 + 2);
673  GetLeafEdges(left, flats);
674  refs.RefIf(first_shared(), left);
675 
676  // Build `right` side tree appending all added flats to `flats`
677  CordRepBtree* right = MakeTree(3);
678  GetLeafEdges(right, flats);
679  refs.RefIf(second_shared(), right);
680 
681  CordRepBtree* tree = use_append ? CordRepBtree::Append(left, right)
682  : CordRepBtree::Prepend(right, left);
683  EXPECT_THAT(tree, IsNode(1));
684  EXPECT_THAT(tree->Edges(), SizeIs(3));
685 
686  // `tree` contains all flats originally belonging to `left` and `right`.
687  EXPECT_THAT(GetLeafEdges(tree), ElementsAreArray(flats));
688  CordRepBtree::Unref(tree);
689  }
690 }
691 
692 TEST_P(CordRepBtreeDualTest, MergeLeafWithTreeExceedingLeafCapacity) {
693  for (bool use_append : {false, true}) {
694  SCOPED_TRACE(use_append ? "Using Append" : "Using Prepend");
695 
696  AutoUnref refs;
697  std::vector<CordRep*> flats;
698 
699  // Build `left` side tree appending all added flats to `flats`
700  CordRepBtree* left = MakeTree(CordRepBtree::kMaxCapacity * 3 - 2);
701  GetLeafEdges(left, flats);
702  refs.RefIf(first_shared(), left);
703 
704  // Build `right` side tree appending all added flats to `flats`
705  CordRepBtree* right = MakeTree(3);
706  GetLeafEdges(right, flats);
707  refs.RefIf(second_shared(), right);
708 
709  CordRepBtree* tree = use_append ? CordRepBtree::Append(left, right)
710  : CordRepBtree::Prepend(right, left);
711  EXPECT_THAT(tree, IsNode(1));
712  EXPECT_THAT(tree->Edges(), SizeIs(4));
713 
714  // `tree` contains all flats originally belonging to `left` and `right`.
715  EXPECT_THAT(GetLeafEdges(tree), ElementsAreArray(flats));
716  CordRepBtree::Unref(tree);
717  }
718 }
719 
720 void RefEdgesAt(size_t depth, AutoUnref& refs, CordRepBtree* tree) {
721  absl::Span<CordRep* const> edges = tree->Edges();
722  if (depth == 0) {
723  refs.Ref(edges.front());
724  refs.Ref(edges.back());
725  } else {
726  assert(tree->height() > 0);
727  RefEdgesAt(depth - 1, refs, edges.front()->btree());
728  RefEdgesAt(depth - 1, refs, edges.back()->btree());
729  }
730 }
731 
732 TEST(CordRepBtreeTest, MergeFuzzTest) {
733  constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
734  std::minstd_rand rnd;
735  std::uniform_int_distribution<int> coin_flip(0, 1);
736  std::uniform_int_distribution<int> dice_throw(1, 6);
737 
738  auto random_leaf_count = [&]() {
739  std::uniform_int_distribution<int> dist_height(0, 3);
740  std::uniform_int_distribution<int> dist_leaf(0, max_cap - 1);
741  const size_t height = dist_height(rnd);
742  return (height ? pow(max_cap, height) : 0) + dist_leaf(rnd);
743  };
744 
745  for (int i = 0; i < 10000; ++i) {
746  AutoUnref refs;
747  std::vector<CordRep*> flats;
748 
749  CordRepBtree* left = MakeTree(random_leaf_count(), coin_flip(rnd));
750  GetLeafEdges(left, flats);
751  if (dice_throw(rnd) == 1) {
752  std::uniform_int_distribution<int> dist(0, left->height());
753  RefEdgesAt(dist(rnd), refs, left);
754  }
755 
756  CordRepBtree* right = MakeTree(random_leaf_count(), coin_flip(rnd));
757  GetLeafEdges(right, flats);
758  if (dice_throw(rnd) == 1) {
759  std::uniform_int_distribution<int> dist(0, right->height());
760  RefEdgesAt(dist(rnd), refs, right);
761  }
762 
763  CordRepBtree* tree = CordRepBtree::Append(left, right);
764  EXPECT_THAT(GetLeafEdges(tree), ElementsAreArray(flats));
765  CordRepBtree::Unref(tree);
766  }
767 }
768 
769 TEST_P(CordRepBtreeTest, RemoveSuffix) {
770  // Create tree of 1, 2 and 3 levels high
771  constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
772  for (size_t cap : {max_cap - 1, max_cap * 2, max_cap * max_cap * 2}) {
773  const std::string data = CreateRandomString(cap * 512);
774 
775  {
776  // Verify RemoveSuffix(<all>)
777  AutoUnref refs;
778  CordRepBtree* node = refs.RefIf(shared(), CreateTree(data, 512));
779  EXPECT_THAT(CordRepBtree::RemoveSuffix(node, data.length()), Eq(nullptr));
780 
781  // Verify RemoveSuffix(<none>)
782  node = refs.RefIf(shared(), CreateTree(data, 512));
783  EXPECT_THAT(CordRepBtree::RemoveSuffix(node, 0), Eq(node));
784  CordRep::Unref(node);
785  }
786 
787  for (int n = 1; n < data.length(); ++n) {
788  AutoUnref refs;
789  auto flats = CreateFlatsFromString(data, 512);
790  CordRepBtree* node = refs.RefIf(shared(), CreateTree(flats));
791  CordRep* rep = refs.Add(CordRepBtree::RemoveSuffix(node, n));
792  EXPECT_THAT(CordToString(rep), Eq(data.substr(0, data.length() - n)));
793 
794  // Collect all flats
795  auto is_flat = [](CordRep* rep) { return rep->tag >= FLAT; };
796  std::vector<CordRep*> edges = CordCollectRepsIf(is_flat, rep);
797  ASSERT_THAT(edges.size(), Le(flats.size()));
798 
799  // Isolate last edge
800  CordRep* last_edge = edges.back();
801  edges.pop_back();
802  const size_t last_length = rep->length - edges.size() * 512;
803 
804  // All flats except the last edge must be kept or copied 'as is'
805  int index = 0;
806  for (CordRep* edge : edges) {
807  ASSERT_THAT(edge, Eq(flats[index++]));
808  ASSERT_THAT(edge->length, Eq(512));
809  }
810 
811  // CordRepBtree may optimize small substrings to avoid waste, so only
812  // check for flat sharing / updates where the code should always do this.
813  if (last_length >= 500) {
814  EXPECT_THAT(last_edge, Eq(flats[index++]));
815  if (shared()) {
816  EXPECT_THAT(last_edge->length, Eq(512));
817  } else {
818  EXPECT_TRUE(last_edge->refcount.IsOne());
819  EXPECT_THAT(last_edge->length, Eq(last_length));
820  }
821  }
822  }
823  }
824 }
825 
826 TEST(CordRepBtreeTest, SubTree) {
827  // Create tree of at least 2 levels high
828  constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
829  const size_t n = max_cap * max_cap * 2;
830  const std::string data = CreateRandomString(n * 3);
831  std::vector<CordRep*> flats;
832  for (absl::string_view s = data; !s.empty(); s.remove_prefix(3)) {
833  flats.push_back(MakeFlat(s.substr(0, 3)));
834  }
835  CordRepBtree* node = CordRepBtree::Create(CordRep::Ref(flats[0]));
836  for (size_t i = 1; i < flats.size(); ++i) {
837  node = CordRepBtree::Append(node, CordRep::Ref(flats[i]));
838  }
839 
840  for (int offset = 0; offset < data.length(); ++offset) {
841  for (int length = 1; length <= data.length() - offset; ++length) {
842  CordRep* rep = node->SubTree(offset, length);
845  }
846  }
847  CordRepBtree::Unref(node);
848  for (CordRep* rep : flats) {
850  }
851 }
852 
853 TEST(CordRepBtreeTest, SubTreeOnExistingSubstring) {
854  // This test verifies that a SubTree call on a pre-existing (large) substring
855  // adjusts the existing substring if not shared, and else rewrites the
856  // existing substring.
857  AutoUnref refs;
859  CordRepBtree* leaf = CordRepBtree::Create(MakeFlat("abc"));
860  CordRep* flat = MakeFlat(data);
861  leaf = CordRepBtree::Append(leaf, flat);
862 
863  // Setup tree containing substring.
864  CordRep* result = leaf->SubTree(0, 3 + 990);
865  ASSERT_THAT(result->tag, Eq(BTREE));
866  CordRep::Unref(leaf);
867  leaf = result->btree();
868  ASSERT_THAT(leaf->Edges(), ElementsAre(_, IsSubstring(0, 990)));
869  EXPECT_THAT(leaf->Edges()[1]->substring()->child, Eq(flat));
870 
871  // Verify substring of substring.
872  result = leaf->SubTree(3 + 5, 970);
873  ASSERT_THAT(result, IsSubstring(5, 970));
874  EXPECT_THAT(result->substring()->child, Eq(flat));
876 
877  CordRep::Unref(leaf);
878 }
879 
880 TEST_P(CordRepBtreeTest, AddDataToLeaf) {
881  const size_t n = CordRepBtree::kMaxCapacity;
882  const std::string data = CreateRandomString(n * 3);
883 
884  for (bool append : {true, false}) {
885  AutoUnref refs;
886  DataConsumer consumer(data, append);
887  SCOPED_TRACE(append ? "Append" : "Prepend");
888 
889  CordRepBtree* leaf = CordRepBtree::Create(MakeFlat(consumer.Next(3)));
890  for (size_t i = 1; i < n; ++i) {
891  refs.RefIf(shared(), leaf);
892  CordRepBtree* result = BtreeAdd(leaf, append, consumer.Next(3));
893  EXPECT_THAT(result, Conditional(shared(), Ne(leaf), Eq(leaf)));
894  EXPECT_THAT(CordToString(result), Eq(consumer.Consumed()));
895  leaf = result;
896  }
897  CordRep::Unref(leaf);
898  }
899 }
900 
901 TEST_P(CordRepBtreeTest, AppendDataToTree) {
902  AutoUnref refs;
905  CordRepBtree* tree = refs.RefIf(shared(), CreateTree(data, 3));
906  CordRepBtree* leaf0 = tree->Edges()[0]->btree();
907  CordRepBtree* leaf1 = tree->Edges()[1]->btree();
908  CordRepBtree* result = CordRepBtree::Append(tree, "123456789");
909  EXPECT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
910  EXPECT_THAT(result->Edges(),
911  ElementsAre(leaf0, Conditional(shared(), Ne(leaf1), Eq(leaf1))));
912  EXPECT_THAT(CordToString(result), Eq(data + "123456789"));
914 }
915 
916 TEST_P(CordRepBtreeTest, PrependDataToTree) {
917  AutoUnref refs;
920  CordRepBtree* tree = refs.RefIf(shared(), CreateTreeReverse(data, 3));
921  CordRepBtree* leaf0 = tree->Edges()[0]->btree();
922  CordRepBtree* leaf1 = tree->Edges()[1]->btree();
923  CordRepBtree* result = CordRepBtree::Prepend(tree, "123456789");
924  EXPECT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
925  EXPECT_THAT(result->Edges(),
926  ElementsAre(Conditional(shared(), Ne(leaf0), Eq(leaf0)), leaf1));
927  EXPECT_THAT(CordToString(result), Eq("123456789" + data));
929 }
930 
931 TEST_P(CordRepBtreeTest, AddDataToTreeThreeLevelsDeep) {
932  constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
933  const size_t n = max_cap * max_cap * max_cap;
934  const std::string data = CreateRandomString(n * 3);
935 
936  for (bool append : {true, false}) {
937  AutoUnref refs;
938  DataConsumer consumer(data, append);
939  SCOPED_TRACE(append ? "Append" : "Prepend");
940 
941  // Fill leaf
942  CordRepBtree* tree = CordRepBtree::Create(MakeFlat(consumer.Next(3)));
943  for (size_t i = 1; i < max_cap; ++i) {
944  tree = BtreeAdd(tree, append, consumer.Next(3));
945  }
946  ASSERT_THAT(CordToString(tree), Eq(consumer.Consumed()));
947 
948  // Fill to maximum at one deep
949  refs.RefIf(shared(), tree);
950  CordRepBtree* result = BtreeAdd(tree, append, consumer.Next(3));
951  ASSERT_THAT(result, IsNode(1));
952  ASSERT_THAT(result, Ne(tree));
953  ASSERT_THAT(CordToString(result), Eq(consumer.Consumed()));
954  tree = result;
955  for (size_t i = max_cap + 1; i < max_cap * max_cap; ++i) {
956  refs.RefIf(shared(), tree);
957  result = BtreeAdd(tree, append, consumer.Next(3));
958  ASSERT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
959  ASSERT_THAT(CordToString(result), Eq(consumer.Consumed()));
960  tree = result;
961  }
962 
963  // Fill to maximum at two deep
964  refs.RefIf(shared(), tree);
965  result = BtreeAdd(tree, append, consumer.Next(3));
966  ASSERT_THAT(result, IsNode(2));
967  ASSERT_THAT(result, Ne(tree));
968  ASSERT_THAT(CordToString(result), Eq(consumer.Consumed()));
969  tree = result;
970  for (size_t i = max_cap * max_cap + 1; i < max_cap * max_cap * max_cap;
971  ++i) {
972  refs.RefIf(shared(), tree);
973  result = BtreeAdd(tree, append, consumer.Next(3));
974  ASSERT_THAT(result, Conditional(shared(), Ne(tree), Eq(tree)));
975  ASSERT_THAT(CordToString(result), Eq(consumer.Consumed()));
976  tree = result;
977  }
978 
979  CordRep::Unref(tree);
980  }
981 }
982 
983 TEST_P(CordRepBtreeTest, AddLargeDataToLeaf) {
984  const size_t max_cap = CordRepBtree::kMaxCapacity;
985  const size_t n = max_cap * max_cap * max_cap * 3 + 2;
987 
988  for (bool append : {true, false}) {
989  AutoUnref refs;
990  SCOPED_TRACE(append ? "Append" : "Prepend");
991 
992  CordRepBtree* leaf = CordRepBtree::Create(MakeFlat("abc"));
993  refs.RefIf(shared(), leaf);
994  CordRepBtree* result = BtreeAdd(leaf, append, data);
995  EXPECT_THAT(CordToString(result), Eq(append ? "abc" + data : data + "abc"));
997  }
998 }
999 
1000 TEST_P(CordRepBtreeTest, CreateFromTreeReturnsTree) {
1001  AutoUnref refs;
1002  CordRepBtree* leaf = CordRepBtree::Create(MakeFlat("Hello world"));
1003  refs.RefIf(shared(), leaf);
1004  CordRepBtree* result = CordRepBtree::Create(leaf);
1005  EXPECT_THAT(result, Eq(leaf));
1007 }
1008 
1009 TEST(CordRepBtreeTest, GetCharacter) {
1012  CordRepBtree* tree = CreateTree(data, 3);
1013  // Add a substring node for good measure.
1014  tree = tree->Append(tree, MakeSubstring(4, 5, MakeFlat("abcdefghijklm")));
1015  data += "efghi";
1016  for (size_t i = 0; i < data.length(); ++i) {
1017  ASSERT_THAT(tree->GetCharacter(i), Eq(data[i]));
1018  }
1019  CordRep::Unref(tree);
1020 }
1021 
1022 TEST_P(CordRepBtreeTest, IsFlatSingleFlat) {
1023  CordRepBtree* leaf = CordRepBtree::Create(MakeFlat("Hello world"));
1024 
1025  absl::string_view fragment;
1026  EXPECT_TRUE(leaf->IsFlat(nullptr));
1027  EXPECT_TRUE(leaf->IsFlat(&fragment));
1028  EXPECT_THAT(fragment, Eq("Hello world"));
1029  fragment = "";
1030  EXPECT_TRUE(leaf->IsFlat(0, 11, nullptr));
1031  EXPECT_TRUE(leaf->IsFlat(0, 11, &fragment));
1032  EXPECT_THAT(fragment, Eq("Hello world"));
1033 
1034  // Arbitrary ranges must check true as well.
1035  EXPECT_TRUE(leaf->IsFlat(1, 4, &fragment));
1036  EXPECT_THAT(fragment, Eq("ello"));
1037  EXPECT_TRUE(leaf->IsFlat(6, 5, &fragment));
1038  EXPECT_THAT(fragment, Eq("world"));
1039 
1040  CordRep::Unref(leaf);
1041 }
1042 
1043 TEST(CordRepBtreeTest, IsFlatMultiFlat) {
1046  CordRepBtree* tree = CreateTree(data, 3);
1047  // Add substring nodes for good measure.
1048  tree = tree->Append(tree, MakeSubstring(4, 3, MakeFlat("abcdefghijklm")));
1049  tree = tree->Append(tree, MakeSubstring(8, 3, MakeFlat("abcdefghijklm")));
1050  data += "efgijk";
1051 
1052  EXPECT_FALSE(tree->IsFlat(nullptr));
1053  absl::string_view fragment = "Can't touch this";
1054  EXPECT_FALSE(tree->IsFlat(&fragment));
1055  EXPECT_THAT(fragment, Eq("Can't touch this"));
1056 
1057  for (size_t offset = 0; offset < data.size(); offset += 3) {
1058  EXPECT_TRUE(tree->IsFlat(offset, 3, nullptr));
1059  EXPECT_TRUE(tree->IsFlat(offset, 3, &fragment));
1060  EXPECT_THAT(fragment, Eq(data.substr(offset, 3)));
1061 
1062  fragment = "Can't touch this";
1063  if (offset > 0) {
1064  EXPECT_FALSE(tree->IsFlat(offset - 1, 4, nullptr));
1065  EXPECT_FALSE(tree->IsFlat(offset - 1, 4, &fragment));
1066  EXPECT_THAT(fragment, Eq("Can't touch this"));
1067  }
1068  if (offset < data.size() - 4) {
1069  EXPECT_FALSE(tree->IsFlat(offset, 4, nullptr));
1070  EXPECT_FALSE(tree->IsFlat(offset, 4, &fragment));
1071  EXPECT_THAT(fragment, Eq("Can't touch this"));
1072  }
1073  }
1074 
1075  CordRep::Unref(tree);
1076 }
1077 
1078 #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
1079 
1080 TEST_P(CordRepBtreeHeightTest, GetAppendBufferNotPrivate) {
1081  CordRepBtree* tree = CordRepBtree::Create(MakeExternal("Foo"));
1082  CordRepBtree::Ref(tree);
1083  EXPECT_DEATH(tree->GetAppendBuffer(1), ".*");
1084  CordRepBtree::Unref(tree);
1085  CordRepBtree::Unref(tree);
1086 }
1087 
1088 #endif // defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
1089 
1090 TEST_P(CordRepBtreeHeightTest, GetAppendBufferNotFlat) {
1091  CordRepBtree* tree = CordRepBtree::Create(MakeExternal("Foo"));
1092  for (int i = 1; i <= height(); ++i) {
1093  tree = CordRepBtree::New(tree);
1094  }
1095  EXPECT_THAT(tree->GetAppendBuffer(1), SizeIs(0));
1096  CordRepBtree::Unref(tree);
1097 }
1098 
1099 TEST_P(CordRepBtreeHeightTest, GetAppendBufferFlatNotPrivate) {
1100  CordRepFlat* flat = MakeFlat("abc");
1101  CordRepBtree* tree = CordRepBtree::Create(CordRep::Ref(flat));
1102  for (int i = 1; i <= height(); ++i) {
1103  tree = CordRepBtree::New(tree);
1104  }
1105  EXPECT_THAT(tree->GetAppendBuffer(1), SizeIs(0));
1106  CordRepBtree::Unref(tree);
1107  CordRep::Unref(flat);
1108 }
1109 
1110 TEST_P(CordRepBtreeHeightTest, GetAppendBufferTreeNotPrivate) {
1111  if (height() == 0) return;
1112  AutoUnref refs;
1113  CordRepFlat* flat = MakeFlat("abc");
1114  CordRepBtree* tree = CordRepBtree::Create(CordRep::Ref(flat));
1115  for (int i = 1; i <= height(); ++i) {
1116  if (i == (height() + 1) / 2) refs.Ref(tree);
1117  tree = CordRepBtree::New(tree);
1118  }
1119  EXPECT_THAT(tree->GetAppendBuffer(1), SizeIs(0));
1120  CordRepBtree::Unref(tree);
1121  CordRep::Unref(flat);
1122 }
1123 
1124 TEST_P(CordRepBtreeHeightTest, GetAppendBufferFlatNoCapacity) {
1125  CordRepFlat* flat = MakeFlat("abc");
1126  flat->length = flat->Capacity();
1127  CordRepBtree* tree = CordRepBtree::Create(flat);
1128  for (int i = 1; i <= height(); ++i) {
1129  tree = CordRepBtree::New(tree);
1130  }
1131  EXPECT_THAT(tree->GetAppendBuffer(1), SizeIs(0));
1132  CordRepBtree::Unref(tree);
1133 }
1134 
1135 TEST_P(CordRepBtreeHeightTest, GetAppendBufferFlatWithCapacity) {
1136  CordRepFlat* flat = MakeFlat("abc");
1137  CordRepBtree* tree = CordRepBtree::Create(flat);
1138  for (int i = 1; i <= height(); ++i) {
1139  tree = CordRepBtree::New(tree);
1140  }
1141  absl::Span<char> span = tree->GetAppendBuffer(2);
1142  EXPECT_THAT(span, SizeIs(2));
1143  EXPECT_THAT(span.data(), TypedEq<void*>(flat->Data() + 3));
1144  EXPECT_THAT(tree->length, Eq(5));
1145 
1146  size_t avail = flat->Capacity() - 5;
1147  span = tree->GetAppendBuffer(avail + 100);
1148  EXPECT_THAT(span, SizeIs(avail));
1149  EXPECT_THAT(span.data(), TypedEq<void*>(flat->Data() + 5));
1150  EXPECT_THAT(tree->length, Eq(5 + avail));
1151 
1152  CordRepBtree::Unref(tree);
1153 }
1154 
1155 TEST(CordRepBtreeTest, Dump) {
1156  // Handles nullptr
1157  std::stringstream ss;
1158  CordRepBtree::Dump(nullptr, ss);
1159  CordRepBtree::Dump(nullptr, "Once upon a label", ss);
1160  CordRepBtree::Dump(nullptr, "Once upon a label", false, ss);
1161  CordRepBtree::Dump(nullptr, "Once upon a label", true, ss);
1162 
1163  // Cover legal edges
1164  CordRepFlat* flat = MakeFlat("Hello world");
1165  CordRepExternal* external = MakeExternal("Hello external");
1166  CordRep* substr_flat = MakeSubstring(1, 6, CordRep::Ref(flat));
1167  CordRep* substr_external = MakeSubstring(2, 7, CordRep::Ref(external));
1168 
1169  // Build tree
1170  CordRepBtree* tree = CordRepBtree::Create(flat);
1171  tree = CordRepBtree::Append(tree, external);
1172  tree = CordRepBtree::Append(tree, substr_flat);
1173  tree = CordRepBtree::Append(tree, substr_external);
1174 
1175  // Repeat until we have a tree
1176  while (tree->height() == 0) {
1177  tree = CordRepBtree::Append(tree, CordRep::Ref(flat));
1178  tree = CordRepBtree::Append(tree, CordRep::Ref(external));
1179  tree = CordRepBtree::Append(tree, CordRep::Ref(substr_flat));
1180  tree = CordRepBtree::Append(tree, CordRep::Ref(substr_external));
1181  }
1182 
1183  for (int api = 0; api <= 3; ++api) {
1184  absl::string_view api_scope;
1185  std::stringstream ss;
1186  switch (api) {
1187  case 0:
1188  api_scope = "Bare";
1189  CordRepBtree::Dump(tree, ss);
1190  break;
1191  case 1:
1192  api_scope = "Label only";
1193  CordRepBtree::Dump(tree, "Once upon a label", ss);
1194  break;
1195  case 2:
1196  api_scope = "Label no content";
1197  CordRepBtree::Dump(tree, "Once upon a label", false, ss);
1198  break;
1199  default:
1200  api_scope = "Label and content";
1201  CordRepBtree::Dump(tree, "Once upon a label", true, ss);
1202  break;
1203  }
1204  SCOPED_TRACE(api_scope);
1205  std::string str = ss.str();
1206 
1207  // Contains Node(depth) / Leaf and private / shared indicators
1208  EXPECT_THAT(str, AllOf(HasSubstr("Node(1)"), HasSubstr("Leaf"),
1209  HasSubstr("Private"), HasSubstr("Shared")));
1210 
1211  // Contains length and start offset of all data edges
1212  EXPECT_THAT(str, AllOf(HasSubstr("len = 11"), HasSubstr("len = 14"),
1213  HasSubstr("len = 6"), HasSubstr("len = 7"),
1214  HasSubstr("start = 1"), HasSubstr("start = 2")));
1215 
1216  // Contains address of all data edges
1217  EXPECT_THAT(
1218  str, AllOf(HasSubstr(absl::StrCat("0x", absl::Hex(flat))),
1219  HasSubstr(absl::StrCat("0x", absl::Hex(external))),
1220  HasSubstr(absl::StrCat("0x", absl::Hex(substr_flat))),
1221  HasSubstr(absl::StrCat("0x", absl::Hex(substr_external)))));
1222 
1223  if (api != 0) {
1224  // Contains label
1225  EXPECT_THAT(str, HasSubstr("Once upon a label"));
1226  }
1227 
1228  if (api != 3) {
1229  // Does not contain contents
1230  EXPECT_THAT(str, Not(AnyOf((HasSubstr("data = \"Hello world\""),
1231  HasSubstr("data = \"Hello external\""),
1232  HasSubstr("data = \"ello w\""),
1233  HasSubstr("data = \"llo ext\"")))));
1234  } else {
1235  // Contains contents
1236  EXPECT_THAT(str, AllOf((HasSubstr("data = \"Hello world\""),
1237  HasSubstr("data = \"Hello external\""),
1238  HasSubstr("data = \"ello w\""),
1239  HasSubstr("data = \"llo ext\""))));
1240  }
1241  }
1242 
1243  CordRep::Unref(tree);
1244 }
1245 
1246 TEST(CordRepBtreeTest, IsValid) {
1248 
1249  CordRepBtree* empty = CordRepBtree::New(0);
1252 
1253  for (bool as_tree : {false, true}) {
1254  CordRepBtree* leaf = CordRepBtree::Create(MakeFlat("abc"));
1255  CordRepBtree* tree = as_tree ? CordRepBtree::New(leaf) : nullptr;
1256  CordRepBtree* check = as_tree ? tree : leaf;
1257 
1259  leaf->length--;
1261  leaf->length++;
1262 
1264  leaf->tag--;
1266  leaf->tag++;
1267 
1268  // Height
1270  leaf->storage[0] = static_cast<uint8_t>(CordRepBtree::kMaxHeight + 1);
1272  leaf->storage[0] = 1;
1274  leaf->storage[0] = 0;
1275 
1276  // Begin
1278  const uint8_t begin = leaf->storage[1];
1279  leaf->storage[1] = static_cast<uint8_t>(CordRepBtree::kMaxCapacity);
1281  leaf->storage[1] = 2;
1283  leaf->storage[1] = begin;
1284 
1285  // End
1287  const uint8_t end = leaf->storage[2];
1288  leaf->storage[2] = static_cast<uint8_t>(CordRepBtree::kMaxCapacity + 1);
1290  leaf->storage[2] = end;
1291 
1292  // DataEdge tag and value
1294  CordRep* const edge = leaf->Edges()[0];
1295  const uint8_t tag = edge->tag;
1296  CordRepBtreeTestPeer::SetEdge(leaf, begin, nullptr);
1298  CordRepBtreeTestPeer::SetEdge(leaf, begin, edge);
1299  edge->tag = BTREE;
1301  edge->tag = tag;
1302 
1303  if (as_tree) {
1305  leaf->length--;
1307  leaf->length++;
1308 
1309  // Height
1311  tree->storage[0] = static_cast<uint8_t>(2);
1313  tree->storage[0] = 1;
1314 
1315  // Btree edge
1317  CordRep* const edge = tree->Edges()[0];
1318  const uint8_t tag = edge->tag;
1319  edge->tag = FLAT;
1321  edge->tag = tag;
1322  }
1323 
1326  }
1327 }
1328 
1329 TEST(CordRepBtreeTest, AssertValid) {
1330  CordRepBtree* tree = CordRepBtree::Create(MakeFlat("abc"));
1331  const CordRepBtree* ctree = tree;
1333  EXPECT_THAT(CordRepBtree::AssertValid(ctree), Eq(ctree));
1334 
1335 #if defined(GTEST_HAS_DEATH_TEST)
1336  CordRepBtree* nulltree = nullptr;
1337  const CordRepBtree* cnulltree = nullptr;
1338  EXPECT_DEBUG_DEATH(
1339  EXPECT_THAT(CordRepBtree::AssertValid(nulltree), Eq(nulltree)), ".*");
1340  EXPECT_DEBUG_DEATH(
1341  EXPECT_THAT(CordRepBtree::AssertValid(cnulltree), Eq(cnulltree)), ".*");
1342 
1343  tree->length--;
1344  EXPECT_DEBUG_DEATH(EXPECT_THAT(CordRepBtree::AssertValid(tree), Eq(tree)),
1345  ".*");
1346  EXPECT_DEBUG_DEATH(EXPECT_THAT(CordRepBtree::AssertValid(ctree), Eq(ctree)),
1347  ".*");
1348  tree->length++;
1349 #endif
1350  CordRep::Unref(tree);
1351 }
1352 
1353 TEST(CordRepBtreeTest, CheckAssertValidShallowVsDeep) {
1354  // Restore exhaustive validation on any exit.
1355  const bool exhaustive_validation = cord_btree_exhaustive_validation.load();
1356  auto cleanup = absl::MakeCleanup([exhaustive_validation] {
1357  cord_btree_exhaustive_validation.store(exhaustive_validation);
1358  });
1359 
1360  // Create a tree of at least 2 levels, and mess with the original flat, which
1361  // should go undetected in shallow mode as the flat is too far away, but
1362  // should be detected in forced non-shallow mode.
1363  CordRep* flat = MakeFlat("abc");
1364  CordRepBtree* tree = CordRepBtree::Create(flat);
1365  constexpr size_t max_cap = CordRepBtree::kMaxCapacity;
1366  const size_t n = max_cap * max_cap * 2;
1367  for (size_t i = 0; i < n; ++i) {
1368  tree = CordRepBtree::Append(tree, MakeFlat("Hello world"));
1369  }
1370  flat->length = 100;
1371 
1372  cord_btree_exhaustive_validation.store(false);
1374  EXPECT_TRUE(CordRepBtree::IsValid(tree, true));
1375  EXPECT_FALSE(CordRepBtree::IsValid(tree, false));
1377  CordRepBtree::AssertValid(tree, true);
1378 #if defined(GTEST_HAS_DEATH_TEST)
1379  EXPECT_DEBUG_DEATH(CordRepBtree::AssertValid(tree, false), ".*");
1380 #endif
1381 
1384  EXPECT_FALSE(CordRepBtree::IsValid(tree, true));
1385  EXPECT_FALSE(CordRepBtree::IsValid(tree, false));
1386 #if defined(GTEST_HAS_DEATH_TEST)
1387  EXPECT_DEBUG_DEATH(CordRepBtree::AssertValid(tree), ".*");
1388  EXPECT_DEBUG_DEATH(CordRepBtree::AssertValid(tree, true), ".*");
1389 #endif
1390 
1391  flat->length = 3;
1392  CordRep::Unref(tree);
1393 }
1394 
1395 TEST_P(CordRepBtreeTest, Rebuild) {
1396  for (size_t size : {3, 8, 100, 10000, 1000000}) {
1397  SCOPED_TRACE(absl::StrCat("Rebuild @", size));
1398 
1399  std::vector<CordRepFlat*> flats;
1400  for (int i = 0; i < size; ++i) {
1401  flats.push_back(CordRepFlat::New(2));
1402  flats.back()->Data()[0] = 'x';
1403  flats.back()->length = 1;
1404  }
1405 
1406  // Build the tree into 'right', and each so many 'split_limit' edges,
1407  // combine 'left' + 'right' into a new 'left', and start a new 'right'.
1408  // This guarantees we get a reasonable amount of chaos in the tree.
1409  size_t split_count = 0;
1410  size_t split_limit = 3;
1411  auto it = flats.begin();
1412  CordRepBtree* left = nullptr;
1413  CordRepBtree* right = CordRepBtree::New(*it);
1414  while (++it != flats.end()) {
1415  if (++split_count >= split_limit) {
1416  split_limit += split_limit / 16;
1417  left = left ? CordRepBtree::Append(left, right) : right;
1418  right = CordRepBtree::New(*it);
1419  } else {
1420  right = CordRepBtree::Append(right, *it);
1421  }
1422  }
1423 
1424  // Finalize tree
1425  left = left ? CordRepBtree::Append(left, right) : right;
1426 
1427  // Rebuild
1428  AutoUnref ref;
1429  left = ref.Add(CordRepBtree::Rebuild(ref.RefIf(shared(), left)));
1431 
1432  // Verify we have the exact same edges in the exact same order.
1433  bool ok = true;
1434  it = flats.begin();
1435  CordVisitReps(left, [&](CordRep* edge) {
1436  if (edge->tag < FLAT) return;
1437  ok = ok && (it != flats.end() && *it++ == edge);
1438  });
1439  EXPECT_TRUE(ok && it == flats.end()) << "Rebuild edges mismatch";
1440  }
1441 }
1442 
1443 // Convenience helper for CordRepBtree::ExtractAppendBuffer
1444 CordRepBtree::ExtractResult ExtractLast(CordRepBtree* input, size_t cap = 1) {
1446 }
1447 
1448 TEST(CordRepBtreeTest, ExtractAppendBufferLeafSingleFlat) {
1449  CordRep* flat = MakeFlat("Abc");
1450  CordRepBtree* leaf = CordRepBtree::Create(flat);
1451  EXPECT_THAT(ExtractLast(leaf), EqExtractResult(nullptr, flat));
1452  CordRep::Unref(flat);
1453 }
1454 
1455 TEST(CordRepBtreeTest, ExtractAppendBufferNodeSingleFlat) {
1456  CordRep* flat = MakeFlat("Abc");
1457  CordRepBtree* leaf = CordRepBtree::Create(flat);
1458  CordRepBtree* node = CordRepBtree::New(leaf);
1459  EXPECT_THAT(ExtractLast(node), EqExtractResult(nullptr, flat));
1460  CordRep::Unref(flat);
1461 }
1462 
1463 TEST(CordRepBtreeTest, ExtractAppendBufferLeafTwoFlats) {
1464  std::vector<CordRep*> flats = CreateFlatsFromString("abcdef", 3);
1465  CordRepBtree* leaf = CreateTree(flats);
1466  EXPECT_THAT(ExtractLast(leaf), EqExtractResult(flats[0], flats[1]));
1467  CordRep::Unref(flats[0]);
1468  CordRep::Unref(flats[1]);
1469 }
1470 
1471 TEST(CordRepBtreeTest, ExtractAppendBufferNodeTwoFlats) {
1472  std::vector<CordRep*> flats = CreateFlatsFromString("abcdef", 3);
1473  CordRepBtree* leaf = CreateTree(flats);
1474  CordRepBtree* node = CordRepBtree::New(leaf);
1475  EXPECT_THAT(ExtractLast(node), EqExtractResult(flats[0], flats[1]));
1476  CordRep::Unref(flats[0]);
1477  CordRep::Unref(flats[1]);
1478 }
1479 
1480 TEST(CordRepBtreeTest, ExtractAppendBufferNodeTwoFlatsInTwoLeafs) {
1481  std::vector<CordRep*> flats = CreateFlatsFromString("abcdef", 3);
1482  CordRepBtree* leaf1 = CordRepBtree::Create(flats[0]);
1483  CordRepBtree* leaf2 = CordRepBtree::Create(flats[1]);
1484  CordRepBtree* node = CordRepBtree::New(leaf1, leaf2);
1485  EXPECT_THAT(ExtractLast(node), EqExtractResult(flats[0], flats[1]));
1486  CordRep::Unref(flats[0]);
1487  CordRep::Unref(flats[1]);
1488 }
1489 
1490 TEST(CordRepBtreeTest, ExtractAppendBufferLeafThreeFlats) {
1491  std::vector<CordRep*> flats = CreateFlatsFromString("abcdefghi", 3);
1492  CordRepBtree* leaf = CreateTree(flats);
1493  EXPECT_THAT(ExtractLast(leaf), EqExtractResult(leaf, flats[2]));
1494  CordRep::Unref(flats[2]);
1495  CordRep::Unref(leaf);
1496 }
1497 
1498 TEST(CordRepBtreeTest, ExtractAppendBufferNodeThreeFlatsRightNoFolding) {
1499  CordRep* flat = MakeFlat("Abc");
1500  std::vector<CordRep*> flats = CreateFlatsFromString("defghi", 3);
1501  CordRepBtree* leaf1 = CordRepBtree::Create(flat);
1502  CordRepBtree* leaf2 = CreateTree(flats);
1503  CordRepBtree* node = CordRepBtree::New(leaf1, leaf2);
1504  EXPECT_THAT(ExtractLast(node), EqExtractResult(node, flats[1]));
1505  EXPECT_THAT(node->Edges(), ElementsAre(leaf1, leaf2));
1506  EXPECT_THAT(leaf1->Edges(), ElementsAre(flat));
1507  EXPECT_THAT(leaf2->Edges(), ElementsAre(flats[0]));
1508  CordRep::Unref(node);
1509  CordRep::Unref(flats[1]);
1510 }
1511 
1512 TEST(CordRepBtreeTest, ExtractAppendBufferNodeThreeFlatsRightLeafFolding) {
1513  CordRep* flat = MakeFlat("Abc");
1514  std::vector<CordRep*> flats = CreateFlatsFromString("defghi", 3);
1515  CordRepBtree* leaf1 = CreateTree(flats);
1516  CordRepBtree* leaf2 = CordRepBtree::Create(flat);
1517  CordRepBtree* node = CordRepBtree::New(leaf1, leaf2);
1518  EXPECT_THAT(ExtractLast(node), EqExtractResult(leaf1, flat));
1519  EXPECT_THAT(leaf1->Edges(), ElementsAreArray(flats));
1520  CordRep::Unref(leaf1);
1521  CordRep::Unref(flat);
1522 }
1523 
1524 TEST(CordRepBtreeTest, ExtractAppendBufferNoCapacity) {
1525  std::vector<CordRep*> flats = CreateFlatsFromString("abcdef", 3);
1526  CordRepBtree* leaf = CreateTree(flats);
1527  size_t avail = flats[1]->flat()->Capacity() - flats[1]->length;
1528  EXPECT_THAT(ExtractLast(leaf, avail + 1), EqExtractResult(leaf, nullptr));
1529  EXPECT_THAT(ExtractLast(leaf, avail), EqExtractResult(flats[0], flats[1]));
1530  CordRep::Unref(flats[0]);
1531  CordRep::Unref(flats[1]);
1532 }
1533 
1534 TEST(CordRepBtreeTest, ExtractAppendBufferNotFlat) {
1535  std::vector<CordRep*> flats = CreateFlatsFromString("abcdef", 3);
1536  auto substr = MakeSubstring(1, 2, flats[1]);
1537  CordRepBtree* leaf = CreateTree({flats[0], substr});
1538  EXPECT_THAT(ExtractLast(leaf), EqExtractResult(leaf, nullptr));
1539  CordRep::Unref(leaf);
1540 }
1541 
1542 TEST(CordRepBtreeTest, ExtractAppendBufferShared) {
1543  std::vector<CordRep*> flats = CreateFlatsFromString("abcdef", 3);
1544  CordRepBtree* leaf = CreateTree(flats);
1545 
1546  CordRep::Ref(flats[1]);
1547  EXPECT_THAT(ExtractLast(leaf), EqExtractResult(leaf, nullptr));
1548  CordRep::Unref(flats[1]);
1549 
1550  CordRep::Ref(leaf);
1551  EXPECT_THAT(ExtractLast(leaf), EqExtractResult(leaf, nullptr));
1552  CordRep::Unref(leaf);
1553 
1554  CordRepBtree* node = CordRepBtree::New(leaf);
1555  CordRep::Ref(node);
1556  EXPECT_THAT(ExtractLast(node), EqExtractResult(node, nullptr));
1557  CordRep::Unref(node);
1558 
1559  CordRep::Unref(node);
1560 }
1561 
1562 } // namespace
1563 } // namespace cord_internal
1565 } // namespace absl
testing::TestParamInfo::param
ParamType param
Definition: bloaty/third_party/googletest/googletest/include/gtest/internal/gtest-param-util.h:60
absl::cordrep_testing::CreateRandomString
std::string CreateRandomString(size_t n)
Definition: cord_rep_test_util.h:69
xds_interop_client.str
str
Definition: xds_interop_client.py:487
EXPECT_FALSE
#define EXPECT_FALSE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1970
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
absl::cordrep_testing::CordCollectRepsIf
std::vector< cord_internal::CordRep * > CordCollectRepsIf(Predicate &&predicate, cord_internal::CordRep *rep)
Definition: cord_rep_test_util.h:121
absl::ABSL_NAMESPACE_BEGIN::MakeSubstring
CordRepSubstring * MakeSubstring(size_t start, size_t len, CordRep *rep)
Definition: abseil-cpp/absl/strings/cord_ring_test.cc:245
regen-readme.it
it
Definition: regen-readme.py:15
absl::cord_internal::CordRepBtree::kMaxCapacity
static constexpr size_t kMaxCapacity
Definition: cord_rep_btree.h:81
cord_data_edge.h
testing::Not
internal::NotMatcher< InnerMatcher > Not(InnerMatcher m)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8926
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
absl::cord_internal::EdgeData
absl::string_view EdgeData(const CordRep *edge)
Definition: cord_data_edge.h:45
absl::cord_internal::CordRepBtree::edges_
CordRep * edges_[kMaxCapacity]
Definition: cord_rep_btree.h:583
begin
char * begin
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1007
absl::cord_internal::CordRep::Unref
static void Unref(CordRep *rep)
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:642
EXPECT_THAT
#define EXPECT_THAT(value, matcher)
absl::cord_internal::CordRepFlat::New
static CordRepFlat * New(size_t len)
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:128
absl::MakeCleanup
absl::Cleanup< cleanup_internal::Tag, Callback > MakeCleanup(Callback callback)
Definition: abseil-cpp/absl/cleanup/cleanup.h:127
absl::Span
Definition: abseil-cpp/absl/types/span.h:152
testing::Ne
internal::NeMatcher< Rhs > Ne(Rhs x)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8609
re2::Dump
static void Dump(StringPiece pattern, Regexp::ParseFlags flags, std::string *forward, std::string *reverse)
Definition: bloaty/third_party/re2/re2/testing/compile_test.cc:242
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
absl::str_format_internal::AllOf
constexpr bool AllOf()
Definition: abseil-cpp/absl/strings/internal/str_format/checker.h:39
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
absl::cord_internal::kMaxFlatLength
static constexpr size_t kMaxFlatLength
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:45
consumed_
size_t consumed_
Definition: cord_rep_btree_test.cc:166
testing::TestParamInfo
Definition: bloaty/third_party/googletest/googletest/include/gtest/internal/gtest-param-util.h:56
absl::TEST
TEST(NotificationTest, SanityTest)
Definition: abseil-cpp/absl/synchronization/notification_test.cc:126
absl::FormatConversionChar::s
@ s
testing::Range
internal::ParamGenerator< T > Range(T start, T end, IncrementT step)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:229
testing::AnyOf
internal::AnyOfResult2< M1, M2 >::type AnyOf(M1 m1, M2 m2)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:13555
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
absl::cord_internal::CordRepBtree::kMaxHeight
static constexpr int kMaxHeight
Definition: cord_rep_btree.h:99
absl::cord_internal::CordRep
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:209
absl::Span::back
constexpr reference back() const noexcept
Definition: abseil-cpp/absl/types/span.h:304
data_
absl::string_view data_
Definition: cord_rep_btree_test.cc:165
absl::cord_internal::CordRepBtree::Prepend
static CordRepBtree * Prepend(CordRepBtree *tree, CordRep *rep)
Definition: cord_rep_btree.h:899
absl::base_internal::Next
static AllocList * Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena)
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:453
testing::ElementsAreArray
internal::ElementsAreArrayMatcher< typename ::std::iterator_traits< Iter >::value_type > ElementsAreArray(Iter first, Iter last)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8465
testing::TestWithParam
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1883
testing::ElementsAre
internal::ElementsAreMatcher< ::testing::tuple<> > ElementsAre()
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:13040
absl::cord_internal::CordRepBtree::RemoveSuffix
static CordRep * RemoveSuffix(CordRepBtree *tree, size_t n)
Definition: cord_rep_btree.cc:828
absl::cord_internal::CordRepBtree::New
static CordRepBtree * New(int height=0)
Definition: cord_rep_btree.h:633
absl::cord_internal::CordRep::tag
uint8_t tag
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:232
absl::ABSL_NAMESPACE_BEGIN::MakeLeaf
CordRep * MakeLeaf(absl::string_view s, size_t extra=0)
Definition: abseil-cpp/absl/strings/cord_ring_test.cc:236
forward_
bool forward_
Definition: cord_rep_btree_test.cc:167
absl::Hex
Definition: abseil-cpp/absl/strings/str_cat.h:134
absl::ToString
absl::string_view ToString(TestCordSize size)
Definition: abseil-cpp/absl/strings/cord_test_helpers.h:59
refs
std::vector< CordRep * > refs
Definition: cordz_info_statistics_test.cc:81
start
static uint64_t start
Definition: benchmark-pound.c:74
absl::cordrep_testing::CreateFlatsFromString
std::vector< cord_internal::CordRep * > CreateFlatsFromString(absl::string_view data, size_t chunk_size)
Definition: cord_rep_test_util.h:86
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
SCOPED_TRACE
#define SCOPED_TRACE(message)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2264
absl::cord_internal::CordRepBtree::Dump
static void Dump(const CordRep *rep, std::ostream &stream)
Definition: cord_rep_btree.cc:380
absl::MATCHER_P
MATCHER_P(HasValidCordzInfoOf, method, "CordzInfo matches cord")
Definition: abseil-cpp/absl/strings/cordz_test_helpers.h:56
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
absl::ABSL_NAMESPACE_BEGIN::MakeFlat
CordRep * MakeFlat(absl::string_view s, size_t extra=0)
Definition: abseil-cpp/absl/strings/cord_ring_test.cc:197
absl::string_view::size
constexpr size_type size() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:277
ToString
std::string ToString(const grpc::string_ref &r)
Definition: string_ref_helper.cc:24
tag
static void * tag(intptr_t t)
Definition: bad_client.cc:318
absl::ABSL_NAMESPACE_BEGIN::RemoveSuffix
CordRepSubstring * RemoveSuffix(size_t length, CordRep *rep)
Definition: abseil-cpp/absl/strings/cord_ring_test.cc:260
absl::synchronization_internal::Edges
std::vector< Edge > Edges
Definition: abseil-cpp/absl/synchronization/internal/graphcycles_test.cc:39
TEST_P
#define TEST_P(test_suite_name, test_name)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:414
ASSERT_THAT
#define ASSERT_THAT(value, matcher)
absl::cord_internal::CordRepBtree::Destroy
static void Destroy(CordRepBtree *tree)
Definition: cord_rep_btree.cc:401
absl::cord_internal::FLAT
@ FLAT
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:194
absl::cord_internal::CordRepBtreeTestPeer
Definition: cord_rep_btree_test.cc:38
testing::Eq
internal::EqMatcher< T > Eq(T x)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8561
gmock_output_test._
_
Definition: bloaty/third_party/googletest/googlemock/test/gmock_output_test.py:175
cord_rep_btree.h
consumer
static void consumer(void *v)
Definition: sync_test.cc:387
arg
Definition: cmdline.cc:40
ref
unsigned ref
Definition: cxa_demangle.cpp:4909
testing::SizeIs
internal::SizeIsMatcher< SizeMatcher > SizeIs(const SizeMatcher &size_matcher)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8947
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
absl::cord_internal::CordRepBtree::Create
static CordRepBtree * Create(CordRep *rep)
Definition: cord_rep_btree.h:831
absl::kZeroPad4
@ kZeroPad4
Definition: abseil-cpp/absl/strings/str_cat.h:89
absl::Span::end
constexpr iterator end() const noexcept
Definition: abseil-cpp/absl/types/span.h:325
absl::cord_internal::CordRepBtree::ExtractAppendBuffer
static ExtractResult ExtractAppendBuffer(CordRepBtree *tree, size_t extra_capacity=1)
Definition: cord_rep_btree.cc:1153
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
absl::cord_internal::CordRepBtreeTestPeer::AddEdge
static void AddEdge(CordRepBtree *node, CordRep *edge)
Definition: cord_rep_btree_test.cc:43
setup.idx
idx
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:197
absl::cord_internal::CordRepBtree::Append
static CordRepBtree * Append(CordRepBtree *tree, CordRep *rep)
Definition: cord_rep_btree.h:892
absl::Span::begin
constexpr iterator begin() const noexcept
Definition: abseil-cpp/absl/types/span.h:312
absl::cordrep_testing::CordVisitReps
void CordVisitReps(cord_internal::CordRep *rep, Fn &&fn)
Definition: cord_rep_test_util.h:107
google_benchmark.example.empty
def empty(state)
Definition: example.py:31
absl::cord_internal::CordRep::length
size_t length
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:228
absl::cord_internal::CordRepBtree::IsValid
static bool IsValid(const CordRepBtree *tree, bool shallow=false)
Definition: cord_rep_btree.cc:417
absl::cord_internal::BTREE
@ BTREE
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:181
absl::cord_internal::CordRepBtreeTestPeer::SetEdge
static void SetEdge(CordRepBtree *node, size_t idx, CordRep *edge)
Definition: cord_rep_btree_test.cc:40
absl::cord_internal::CordRep::btree
CordRepBtree * btree()
Definition: cord_rep_btree.h:589
absl::cord_internal::CordRepBtree
Definition: cord_rep_btree.h:63
absl::cord_internal::CordRepBtree::Rebuild
static CordRepBtree * Rebuild(CordRepBtree *tree)
Definition: cord_rep_btree.cc:1134
testing::Le
internal::LeMatcher< Rhs > Le(Rhs x)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8597
testing::TypedEq
Matcher< Lhs > TypedEq(const Rhs &rhs)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8581
index
int index
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:1184
testing::Combine
internal::CartesianProductHolder< Generator... > Combine(const Generator &... g)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:410
absl::cord_internal::SUBSTRING
@ SUBSTRING
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:179
testing::IsSubstring
GTEST_API_ AssertionResult IsSubstring(const char *needle_expr, const char *haystack_expr, const char *needle, const char *haystack)
Definition: bloaty/third_party/googletest/googletest/src/gtest.cc:1617
ASSERT_TRUE
#define ASSERT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1973
rep
const CordRep * rep
Definition: cord_analysis.cc:53
ok
bool ok
Definition: async_end2end_test.cc:197
absl::cord_internal::CordRep::Ref
static CordRep * Ref(CordRep *rep)
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:634
check
static void check(upb_inttable *t)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:1715
absl::cord_internal::CordRepBtree::AssertValid
static CordRepBtree * AssertValid(CordRepBtree *tree, bool shallow=true)
Definition: cord_rep_btree.cc:462
input
std::string input
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer_unittest.cc:197
EXPECT_TRUE
#define EXPECT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1967
absl::cord_internal::IsDataEdge
bool IsDataEdge(const CordRep *edge)
Definition: cord_data_edge.h:32
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::forward
constexpr T && forward(absl::remove_reference_t< T > &t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:230
cleanup
Definition: cleanup.py:1
absl::ABSL_NAMESPACE_BEGIN::MakeExternal
CordRepExternal * MakeExternal(absl::string_view s)
Definition: abseil-cpp/absl/strings/cord_ring_test.cc:205
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
absl::MATCHER_P2
MATCHER_P2(CordzMethodCountEq, method, n, absl::StrCat("CordzInfo method count equals ", n))
Definition: abseil-cpp/absl/strings/cordz_test_helpers.h:82
length
std::size_t length
Definition: abseil-cpp/absl/time/internal/test_util.cc:57
mkowners.depth
depth
Definition: mkowners.py:114
testing::Bool
internal::ParamGenerator< bool > Bool()
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:359
absl::cord_internal::CordRepBtree::Unref
static void Unref(absl::Span< CordRep *const > edges)
Definition: cord_rep_btree.h:660
absl::cord_internal::cord_btree_exhaustive_validation
std::atomic< bool > cord_btree_exhaustive_validation
absl::cordrep_testing::CordToString
void CordToString(cord_internal::CordRep *rep, std::string &s)
Definition: cord_rep_test_util.h:138
testing::HasSubstr
PolymorphicMatcher< internal::HasSubstrMatcher< internal::string > > HasSubstr(const internal::string &substring)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8803
cord_rep_test_util.h
absl::Span::data
constexpr pointer data() const noexcept
Definition: abseil-cpp/absl/types/span.h:256
absl::string_view::substr
constexpr string_view substr(size_type pos=0, size_type n=npos) const
Definition: abseil-cpp/absl/strings/string_view.h:399
absl::cord_internal::CordRepBtree::fetch_add_end
size_t fetch_add_end(size_t n)
Definition: cord_rep_btree.h:399
absl::Span::front
constexpr reference front() const noexcept
Definition: abseil-cpp/absl/types/span.h:296
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
offset
voidpf uLong offset
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:142
height
int height
Definition: libuv/docs/code/tty-gravity/main.c:10
INSTANTIATE_TEST_SUITE_P
#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name,...)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:460


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:03