cord_rep_btree.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 <cassert>
18 #include <cstdint>
19 #include <iostream>
20 #include <string>
21 
22 #include "absl/base/attributes.h"
23 #include "absl/base/config.h"
24 #include "absl/base/internal/raw_logging.h"
26 #include "absl/strings/internal/cord_internal.h"
28 #include "absl/strings/internal/cord_rep_flat.h"
29 #include "absl/strings/str_cat.h"
30 #include "absl/strings/string_view.h"
31 
32 namespace absl {
34 namespace cord_internal {
35 
36 #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
37 constexpr size_t CordRepBtree::kMaxCapacity;
38 #endif
39 
40 namespace {
41 
42 using NodeStack = CordRepBtree * [CordRepBtree::kMaxDepth];
43 using EdgeType = CordRepBtree::EdgeType;
44 using OpResult = CordRepBtree::OpResult;
45 using CopyResult = CordRepBtree::CopyResult;
46 
47 constexpr auto kFront = CordRepBtree::kFront;
48 constexpr auto kBack = CordRepBtree::kBack;
49 
50 inline bool exhaustive_validation() {
51  return cord_btree_exhaustive_validation.load(std::memory_order_relaxed);
52 }
53 
54 // Implementation of the various 'Dump' functions.
55 // Prints the entire tree structure or 'rep'. External callers should
56 // not specify 'depth' and leave it to its default (0) value.
57 // Rep may be a CordRepBtree tree, or a SUBSTRING / EXTERNAL / FLAT node.
58 void DumpAll(const CordRep* rep, bool include_contents, std::ostream& stream,
59  int depth = 0) {
60  // Allow for full height trees + substring -> flat / external nodes.
61  assert(depth <= CordRepBtree::kMaxDepth + 2);
62  std::string sharing = const_cast<CordRep*>(rep)->refcount.IsOne()
63  ? std::string("Private")
64  : absl::StrCat("Shared(", rep->refcount.Get(), ")");
65  std::string sptr = absl::StrCat("0x", absl::Hex(rep));
66 
67  // Dumps the data contents of `rep` if `include_contents` is true.
68  // Always emits a new line character.
69  auto maybe_dump_data = [&stream, include_contents](const CordRep* r) {
70  if (include_contents) {
71  // Allow for up to 60 wide display of content data, which with some
72  // indentation and prefix / labels keeps us within roughly 80-100 wide.
73  constexpr size_t kMaxDataLength = 60;
74  stream << ", data = \""
75  << EdgeData(r).substr(0, kMaxDataLength)
76  << (r->length > kMaxDataLength ? "\"..." : "\"");
77  }
78  stream << '\n';
79  };
80 
81  // For each level, we print the 'shared/private' state and the rep pointer,
82  // indented by two spaces per recursive depth.
83  stream << std::string(depth * 2, ' ') << sharing << " (" << sptr << ") ";
84 
85  if (rep->IsBtree()) {
86  const CordRepBtree* node = rep->btree();
88  node->height() ? absl::StrCat("Node(", node->height(), ")") : "Leaf";
89  stream << label << ", len = " << node->length
90  << ", begin = " << node->begin() << ", end = " << node->end()
91  << "\n";
92  for (CordRep* edge : node->Edges()) {
93  DumpAll(edge, include_contents, stream, depth + 1);
94  }
95  } else if (rep->tag == SUBSTRING) {
96  const CordRepSubstring* substring = rep->substring();
97  stream << "Substring, len = " << rep->length
98  << ", start = " << substring->start;
99  maybe_dump_data(rep);
100  DumpAll(substring->child, include_contents, stream, depth + 1);
101  } else if (rep->tag >= FLAT) {
102  stream << "Flat, len = " << rep->length
103  << ", cap = " << rep->flat()->Capacity();
104  maybe_dump_data(rep);
105  } else if (rep->tag == EXTERNAL) {
106  stream << "Extn, len = " << rep->length;
107  maybe_dump_data(rep);
108  }
109 }
110 
111 // TODO(b/192061034): add 'bytes to copy' logic to avoid large slop on substring
112 // small data out of large reps, and general efficiency of 'always copy small
113 // data'. Consider making this a cord rep internal library function.
114 CordRepSubstring* CreateSubstring(CordRep* rep, size_t offset, size_t n) {
115  assert(n != 0);
116  assert(offset + n <= rep->length);
117  assert(offset != 0 || n != rep->length);
118 
119  if (rep->tag == SUBSTRING) {
120  CordRepSubstring* substring = rep->substring();
121  offset += substring->start;
122  rep = CordRep::Ref(substring->child);
123  CordRep::Unref(substring);
124  }
125  assert(rep->IsExternal() || rep->IsFlat());
126  CordRepSubstring* substring = new CordRepSubstring();
127  substring->length = n;
128  substring->tag = SUBSTRING;
129  substring->start = offset;
130  substring->child = rep;
131  return substring;
132 }
133 
134 // TODO(b/192061034): consider making this a cord rep library function.
135 inline CordRep* MakeSubstring(CordRep* rep, size_t offset, size_t n) {
136  if (n == rep->length) return rep;
137  if (n == 0) return CordRep::Unref(rep), nullptr;
138  return CreateSubstring(rep, offset, n);
139 }
140 
141 // TODO(b/192061034): consider making this a cord rep library function.
142 inline CordRep* MakeSubstring(CordRep* rep, size_t offset) {
143  if (offset == 0) return rep;
144  return CreateSubstring(rep, offset, rep->length - offset);
145 }
146 
147 // Resizes `edge` to the provided `length`. Adopts a reference on `edge`.
148 // This method directly returns `edge` if `length` equals `edge->length`.
149 // If `is_mutable` is set to true, this function may return `edge` with
150 // `edge->length` set to the new length depending on the type and size of
151 // `edge`. Otherwise, this function returns a new CordRepSubstring value.
152 // Requires `length > 0 && length <= edge->length`.
153 CordRep* ResizeEdge(CordRep* edge, size_t length, bool is_mutable) {
154  assert(length > 0);
155  assert(length <= edge->length);
156  assert(IsDataEdge(edge));
157  if (length >= edge->length) return edge;
158 
159  if (is_mutable && (edge->tag >= FLAT || edge->tag == SUBSTRING)) {
160  edge->length = length;
161  return edge;
162  }
163 
164  return CreateSubstring(edge, 0, length);
165 }
166 
167 template <EdgeType edge_type>
168 inline absl::string_view Consume(absl::string_view s, size_t n) {
169  return edge_type == kBack ? s.substr(n) : s.substr(0, s.size() - n);
170 }
171 
172 template <EdgeType edge_type>
173 inline absl::string_view Consume(char* dst, absl::string_view s, size_t n) {
174  if (edge_type == kBack) {
175  memcpy(dst, s.data(), n);
176  return s.substr(n);
177  } else {
178  const size_t offset = s.size() - n;
179  memcpy(dst, s.data() + offset, n);
180  return s.substr(0, offset);
181  }
182 }
183 
184 // Known issue / optimization weirdness: the store associated with the
185 // decrement introduces traffic between cpus (even if the result of that
186 // traffic does nothing), making this faster than a single call to
187 // refcount.Decrement() checking the zero refcount condition.
188 template <typename R, typename Fn>
189 inline void FastUnref(R* r, Fn&& fn) {
190  if (r->refcount.IsOne()) {
191  fn(r);
192  } else if (!r->refcount.DecrementExpectHighRefcount()) {
193  fn(r);
194  }
195 }
196 
197 
198 void DeleteSubstring(CordRepSubstring* substring) {
199  CordRep* rep = substring->child;
200  if (!rep->refcount.Decrement()) {
201  if (rep->tag >= FLAT) {
203  } else {
204  assert(rep->tag == EXTERNAL);
206  }
207  }
208  delete substring;
209 }
210 
211 // Deletes a leaf node data edge. Requires `IsDataEdge(rep)`.
212 void DeleteLeafEdge(CordRep* rep) {
213  assert(IsDataEdge(rep));
214  if (rep->tag >= FLAT) {
216  } else if (rep->tag == EXTERNAL) {
218  } else {
219  DeleteSubstring(rep->substring());
220  }
221 }
222 
223 // StackOperations contains the logic to build a left-most or right-most stack
224 // (leg) down to the leaf level of a btree, and 'unwind' / 'Finalize' methods to
225 // propagate node changes up the stack.
226 template <EdgeType edge_type>
227 struct StackOperations {
228  // Returns true if the node at 'depth' is not shared, i.e. has a refcount
229  // of one and all of its parent nodes have a refcount of one.
230  inline bool owned(int depth) const { return depth < share_depth; }
231 
232  // Returns the node at 'depth'.
233  inline CordRepBtree* node(int depth) const { return stack[depth]; }
234 
235  // Builds a `depth` levels deep stack starting at `tree` recording which nodes
236  // are private in the form of the 'share depth' where nodes are shared.
237  inline CordRepBtree* BuildStack(CordRepBtree* tree, int depth) {
238  assert(depth <= tree->height());
239  int current_depth = 0;
240  while (current_depth < depth && tree->refcount.IsOne()) {
241  stack[current_depth++] = tree;
242  tree = tree->Edge(edge_type)->btree();
243  }
244  share_depth = current_depth + (tree->refcount.IsOne() ? 1 : 0);
245  while (current_depth < depth) {
246  stack[current_depth++] = tree;
247  tree = tree->Edge(edge_type)->btree();
248  }
249  return tree;
250  }
251 
252  // Builds a stack with the invariant that all nodes are private owned / not
253  // shared. This is used in iterative updates where a previous propagation
254  // guaranteed all nodes are owned / private.
255  inline void BuildOwnedStack(CordRepBtree* tree, int height) {
256  assert(height <= CordRepBtree::kMaxHeight);
257  int depth = 0;
258  while (depth < height) {
259  assert(tree->refcount.IsOne());
260  stack[depth++] = tree;
261  tree = tree->Edge(edge_type)->btree();
262  }
263  assert(tree->refcount.IsOne());
264  share_depth = depth + 1;
265  }
266 
267  // Processes the final 'top level' result action for the tree.
268  // See the 'Action' enum for the various action implications.
269  static inline CordRepBtree* Finalize(CordRepBtree* tree, OpResult result) {
270  switch (result.action) {
272  tree = edge_type == kBack ? CordRepBtree::New(tree, result.tree)
273  : CordRepBtree::New(result.tree, tree);
274  if (ABSL_PREDICT_FALSE(tree->height() > CordRepBtree::kMaxHeight)) {
275  tree = CordRepBtree::Rebuild(tree);
276  ABSL_RAW_CHECK(tree->height() <= CordRepBtree::kMaxHeight,
277  "Max height exceeded");
278  }
279  return tree;
281  CordRep::Unref(tree);
283  case CordRepBtree::kSelf:
284  return result.tree;
285  }
287  return result.tree;
288  }
289 
290  // Propagate the action result in 'result' up into all nodes of the stack
291  // starting at depth 'depth'. 'length' contains the extra length of data that
292  // was added at the lowest level, and is updated into all nodes of the stack.
293  // See the 'Action' enum for the various action implications.
294  // If 'propagate' is true, then any copied node values are updated into the
295  // stack, which is used for iterative processing on the same stack.
296  template <bool propagate = false>
297  inline CordRepBtree* Unwind(CordRepBtree* tree, int depth, size_t length,
298  OpResult result) {
299  // TODO(mvels): revisit the below code to check if 3 loops with 3
300  // (incremental) conditions is faster than 1 loop with a switch.
301  // Benchmarking and perf recordings indicate the loop with switch is
302  // fastest, likely because of indirect jumps on the tight case values and
303  // dense branches. But it's worth considering 3 loops, as the `action`
304  // transitions are mono directional. E.g.:
305  // while (action == kPopped) {
306  // ...
307  // }
308  // while (action == kCopied) {
309  // ...
310  // }
311  // ...
312  // We also found that an "if () do {}" loop here seems faster, possibly
313  // because it allows the branch predictor more granular heuristics on
314  // 'single leaf' (`depth` == 0) and 'single depth' (`depth` == 1) cases
315  // which appear to be the most common use cases.
316  if (depth != 0) {
317  do {
318  CordRepBtree* node = stack[--depth];
319  const bool owned = depth < share_depth;
320  switch (result.action) {
322  assert(!propagate);
323  result = node->AddEdge<edge_type>(owned, result.tree, length);
324  break;
326  result = node->SetEdge<edge_type>(owned, result.tree, length);
327  if (propagate) stack[depth] = result.tree;
328  break;
329  case CordRepBtree::kSelf:
330  node->length += length;
331  while (depth > 0) {
332  node = stack[--depth];
333  node->length += length;
334  }
335  return node;
336  }
337  } while (depth > 0);
338  }
339  return Finalize(tree, result);
340  }
341 
342  // Invokes `Unwind` with `propagate=true` to update the stack node values.
343  inline CordRepBtree* Propagate(CordRepBtree* tree, int depth, size_t length,
344  OpResult result) {
345  return Unwind</*propagate=*/true>(tree, depth, length, result);
346  }
347 
348  // `share_depth` contains the depth at which the nodes in the stack become
349  // shared. I.e., if the top most level is shared (i.e.: `!refcount.IsOne()`),
350  // then `share_depth` is 0. If the 2nd node is shared (and implicitly all
351  // nodes below that) then `share_depth` is 1, etc. A `share_depth` greater
352  // than the depth of the stack indicates that none of the nodes in the stack
353  // are shared.
355 
356  NodeStack stack;
357 };
358 
359 } // namespace
360 
362  bool include_contents, std::ostream& stream) {
363  stream << "===================================\n";
364  if (!label.empty()) {
365  stream << label << '\n';
366  stream << "-----------------------------------\n";
367  }
368  if (rep) {
369  DumpAll(rep, include_contents, stream);
370  } else {
371  stream << "NULL\n";
372  }
373 }
374 
376  std::ostream& stream) {
377  Dump(rep, label, false, stream);
378 }
379 
380 void CordRepBtree::Dump(const CordRep* rep, std::ostream& stream) {
381  Dump(rep, absl::string_view(), false, stream);
382 }
383 
384 template <size_t size>
385 static void DestroyTree(CordRepBtree* tree) {
386  for (CordRep* node : tree->Edges()) {
387  if (node->refcount.Decrement()) continue;
388  for (CordRep* edge : node->btree()->Edges()) {
389  if (edge->refcount.Decrement()) continue;
390  if (size == 1) {
391  DeleteLeafEdge(edge);
392  } else {
393  CordRepBtree::Destroy(edge->btree());
394  }
395  }
396  CordRepBtree::Delete(node->btree());
397  }
398  CordRepBtree::Delete(tree);
399 }
400 
402  switch (tree->height()) {
403  case 0:
404  for (CordRep* edge : tree->Edges()) {
405  if (!edge->refcount.Decrement()) {
406  DeleteLeafEdge(edge);
407  }
408  }
409  return CordRepBtree::Delete(tree);
410  case 1:
411  return DestroyTree<1>(tree);
412  default:
413  return DestroyTree<2>(tree);
414  }
415 }
416 
417 bool CordRepBtree::IsValid(const CordRepBtree* tree, bool shallow) {
418 #define NODE_CHECK_VALID(x) \
419  if (!(x)) { \
420  ABSL_RAW_LOG(ERROR, "CordRepBtree::CheckValid() FAILED: %s", #x); \
421  return false; \
422  }
423 #define NODE_CHECK_EQ(x, y) \
424  if ((x) != (y)) { \
425  ABSL_RAW_LOG(ERROR, \
426  "CordRepBtree::CheckValid() FAILED: %s != %s (%s vs %s)", #x, \
427  #y, absl::StrCat(x).c_str(), absl::StrCat(y).c_str()); \
428  return false; \
429  }
430 
431  NODE_CHECK_VALID(tree != nullptr);
432  NODE_CHECK_VALID(tree->IsBtree());
433  NODE_CHECK_VALID(tree->height() <= kMaxHeight);
434  NODE_CHECK_VALID(tree->begin() < tree->capacity());
435  NODE_CHECK_VALID(tree->end() <= tree->capacity());
436  NODE_CHECK_VALID(tree->begin() <= tree->end());
437  size_t child_length = 0;
438  for (CordRep* edge : tree->Edges()) {
439  NODE_CHECK_VALID(edge != nullptr);
440  if (tree->height() > 0) {
441  NODE_CHECK_VALID(edge->IsBtree());
442  NODE_CHECK_VALID(edge->btree()->height() == tree->height() - 1);
443  } else {
445  }
446  child_length += edge->length;
447  }
448  NODE_CHECK_EQ(child_length, tree->length);
449  if ((!shallow || exhaustive_validation()) && tree->height() > 0) {
450  for (CordRep* edge : tree->Edges()) {
451  if (!IsValid(edge->btree(), shallow)) return false;
452  }
453  }
454  return true;
455 
456 #undef NODE_CHECK_VALID
457 #undef NODE_CHECK_EQ
458 }
459 
460 #ifndef NDEBUG
461 
463  if (!IsValid(tree, shallow)) {
464  Dump(tree, "CordRepBtree validation failed:", false, std::cout);
465  ABSL_RAW_LOG(FATAL, "CordRepBtree::CheckValid() FAILED");
466  }
467  return tree;
468 }
469 
471  bool shallow) {
472  if (!IsValid(tree, shallow)) {
473  Dump(tree, "CordRepBtree validation failed:", false, std::cout);
474  ABSL_RAW_LOG(FATAL, "CordRepBtree::CheckValid() FAILED");
475  }
476  return tree;
477 }
478 
479 #endif // NDEBUG
480 
481 template <EdgeType edge_type>
482 inline OpResult CordRepBtree::AddEdge(bool owned, CordRep* edge, size_t delta) {
483  if (size() >= kMaxCapacity) return {New(edge), kPopped};
485  result.tree->Add<edge_type>(edge);
486  result.tree->length += delta;
487  return result;
488 }
489 
490 template <EdgeType edge_type>
491 OpResult CordRepBtree::SetEdge(bool owned, CordRep* edge, size_t delta) {
493  const size_t idx = index(edge_type);
494  if (owned) {
495  result = {this, kSelf};
497  } else {
498  // Create a copy containing all unchanged edges. Unchanged edges are the
499  // open interval [begin, back) or [begin + 1, end) depending on `edge_type`.
500  // We conveniently cover both case using a constexpr `shift` being 0 or 1
501  // as `end :== back + 1`.
502  result = {CopyRaw(), kCopied};
503  constexpr int shift = edge_type == kFront ? 1 : 0;
504  for (CordRep* r : Edges(begin() + shift, back() + shift)) {
505  CordRep::Ref(r);
506  }
507  }
508  result.tree->edges_[idx] = edge;
509  result.tree->length += delta;
510  return result;
511 }
512 
513 template <EdgeType edge_type>
515  const int depth = tree->height();
516  const size_t length = rep->length;
517  StackOperations<edge_type> ops;
518  CordRepBtree* leaf = ops.BuildStack(tree, depth);
519  const OpResult result =
520  leaf->AddEdge<edge_type>(ops.owned(depth), rep, length);
521  return ops.Unwind(tree, depth, length, result);
522 }
523 
524 template <>
525 CordRepBtree* CordRepBtree::NewLeaf<kBack>(absl::string_view data,
526  size_t extra) {
527  CordRepBtree* leaf = CordRepBtree::New(0);
528  size_t length = 0;
529  size_t end = 0;
530  const size_t cap = leaf->capacity();
531  while (!data.empty() && end != cap) {
532  auto* flat = CordRepFlat::New(data.length() + extra);
533  flat->length = (std::min)(data.length(), flat->Capacity());
534  length += flat->length;
535  leaf->edges_[end++] = flat;
536  data = Consume<kBack>(flat->Data(), data, flat->length);
537  }
538  leaf->length = length;
539  leaf->set_end(end);
540  return leaf;
541 }
542 
543 template <>
544 CordRepBtree* CordRepBtree::NewLeaf<kFront>(absl::string_view data,
545  size_t extra) {
546  CordRepBtree* leaf = CordRepBtree::New(0);
547  size_t length = 0;
548  size_t begin = leaf->capacity();
549  leaf->set_end(leaf->capacity());
550  while (!data.empty() && begin != 0) {
551  auto* flat = CordRepFlat::New(data.length() + extra);
552  flat->length = (std::min)(data.length(), flat->Capacity());
553  length += flat->length;
554  leaf->edges_[--begin] = flat;
555  data = Consume<kFront>(flat->Data(), data, flat->length);
556  }
557  leaf->length = length;
558  leaf->set_begin(begin);
559  return leaf;
560 }
561 
562 template <>
563 absl::string_view CordRepBtree::AddData<kBack>(absl::string_view data,
564  size_t extra) {
565  assert(!data.empty());
566  assert(size() < capacity());
567  AlignBegin();
568  const size_t cap = capacity();
569  do {
570  CordRepFlat* flat = CordRepFlat::New(data.length() + extra);
571  const size_t n = (std::min)(data.length(), flat->Capacity());
572  flat->length = n;
573  edges_[fetch_add_end(1)] = flat;
574  data = Consume<kBack>(flat->Data(), data, n);
575  } while (!data.empty() && end() != cap);
576  return data;
577 }
578 
579 template <>
580 absl::string_view CordRepBtree::AddData<kFront>(absl::string_view data,
581  size_t extra) {
582  assert(!data.empty());
583  assert(size() < capacity());
584  AlignEnd();
585  do {
586  CordRepFlat* flat = CordRepFlat::New(data.length() + extra);
587  const size_t n = (std::min)(data.length(), flat->Capacity());
588  flat->length = n;
590  data = Consume<kFront>(flat->Data(), data, n);
591  } while (!data.empty() && begin() != 0);
592  return data;
593 }
594 
595 template <EdgeType edge_type>
597  size_t extra) {
598  if (ABSL_PREDICT_FALSE(data.empty())) return tree;
599 
600  const size_t original_data_size = data.size();
601  int depth = tree->height();
602  StackOperations<edge_type> ops;
603  CordRepBtree* leaf = ops.BuildStack(tree, depth);
604 
605  // If there is capacity in the last edge, append as much data
606  // as possible into this last edge.
607  if (leaf->size() < leaf->capacity()) {
608  OpResult result = leaf->ToOpResult(ops.owned(depth));
609  data = result.tree->AddData<edge_type>(data, extra);
610  if (data.empty()) {
611  result.tree->length += original_data_size;
612  return ops.Unwind(tree, depth, original_data_size, result);
613  }
614 
615  // We added some data into this leaf, but not all. Propagate the added
616  // length to the top most node, and rebuild the stack with any newly copied
617  // or updated nodes. From this point on, the path (leg) from the top most
618  // node to the right-most node towards the leaf node is privately owned.
619  size_t delta = original_data_size - data.size();
620  assert(delta > 0);
621  result.tree->length += delta;
622  tree = ops.Propagate(tree, depth, delta, result);
623  ops.share_depth = depth + 1;
624  }
625 
626  // We were unable to append all data into the existing right-most leaf node.
627  // This means all remaining data must be put into (a) new leaf node(s) which
628  // we append to the tree. To make this efficient, we iteratively build full
629  // leaf nodes from `data` until the created leaf contains all remaining data.
630  // We utilize the `Unwind` method to merge the created leaf into the first
631  // level towards root that has capacity. On each iteration with remaining
632  // data, we rebuild the stack in the knowledge that right-most nodes are
633  // privately owned after the first `Unwind` completes.
634  for (;;) {
635  OpResult result = {CordRepBtree::NewLeaf<edge_type>(data, extra), kPopped};
636  if (result.tree->length == data.size()) {
637  return ops.Unwind(tree, depth, result.tree->length, result);
638  }
639  data = Consume<edge_type>(data, result.tree->length);
640  tree = ops.Unwind(tree, depth, result.tree->length, result);
641  depth = tree->height();
642  ops.BuildOwnedStack(tree, depth);
643  }
644 }
645 
646 template <EdgeType edge_type>
648  assert(dst->height() >= src->height());
649 
650  // Capture source length as we may consume / destroy `src`.
651  const size_t length = src->length;
652 
653  // We attempt to merge `src` at its corresponding height in `dst`.
654  const int depth = dst->height() - src->height();
655  StackOperations<edge_type> ops;
656  CordRepBtree* merge_node = ops.BuildStack(dst, depth);
657 
658  // If there is enough space in `merge_node` for all edges from `src`, add all
659  // edges to this node, making a fresh copy as needed if not privately owned.
660  // If `merge_node` does not have capacity for `src`, we rely on `Unwind` and
661  // `Finalize` to merge `src` into the first level towards `root` where there
662  // is capacity for another edge, or create a new top level node.
664  if (merge_node->size() + src->size() <= kMaxCapacity) {
665  result = merge_node->ToOpResult(ops.owned(depth));
666  result.tree->Add<edge_type>(src->Edges());
667  result.tree->length += src->length;
668  if (src->refcount.IsOne()) {
669  Delete(src);
670  } else {
671  for (CordRep* edge : src->Edges()) CordRep::Ref(edge);
672  CordRepBtree::Unref(src);
673  }
674  } else {
675  result = {src, kPopped};
676  }
677 
678  // Unless we merged at the top level (i.e.: src and dst are equal height),
679  // unwind the result towards the top level, and finalize the result.
680  if (depth) {
681  return ops.Unwind(dst, depth, length, result);
682  }
683  return ops.Finalize(dst, result);
684 }
685 
687  assert(offset < this->length);
688 
689  // As long as `offset` starts inside the last edge, we can 'drop' the current
690  // depth. For the most extreme example: if offset references the last data
691  // edge in the tree, there is only a single edge / path from the top of the
692  // tree to that last edge, so we can drop all the nodes except that edge.
693  // The fast path check for this is `back->length >= length - offset`.
694  int height = this->height();
695  CordRepBtree* node = this;
696  size_t len = node->length - offset;
697  CordRep* back = node->Edge(kBack);
698  while (back->length >= len) {
699  offset = back->length - len;
700  if (--height < 0) {
702  }
703  node = back->btree();
704  back = node->Edge(kBack);
705  }
706  if (offset == 0) return {CordRep::Ref(node), height};
707 
708  // Offset does not point into the last edge, so we span at least two edges.
709  // Find the index of offset with `IndexBeyond` which provides us the edge
710  // 'beyond' the offset if offset is not a clean starting point of an edge.
711  Position pos = node->IndexBeyond(offset);
712  CordRepBtree* sub = node->CopyToEndFrom(pos.index, len);
713  const CopyResult result = {sub, height};
714 
715  // `pos.n` contains a non zero value if the offset is not an exact starting
716  // point of an edge. In this case, `pos.n` contains the 'trailing' amount of
717  // bytes of the edge preceding that in `pos.index`. We need to iteratively
718  // adjust the preceding edge with the 'broken' offset until we have a perfect
719  // start of the edge.
720  while (pos.n != 0) {
721  assert(pos.index >= 1);
722  const size_t begin = pos.index - 1;
723  sub->set_begin(begin);
724  CordRep* const edge = node->Edge(begin);
725 
726  len = pos.n;
727  offset = edge->length - len;
728 
729  if (--height < 0) {
730  sub->edges_[begin] = MakeSubstring(CordRep::Ref(edge), offset, len);
731  return result;
732  }
733 
734  node = edge->btree();
735  pos = node->IndexBeyond(offset);
736 
737  CordRepBtree* nsub = node->CopyToEndFrom(pos.index, len);
738  sub->edges_[begin] = nsub;
739  sub = nsub;
740  }
741  sub->set_begin(pos.index);
742  return result;
743 }
744 
745 CopyResult CordRepBtree::CopyPrefix(size_t n, bool allow_folding) {
746  assert(n > 0);
747  assert(n <= this->length);
748 
749  // As long as `n` does not exceed the length of the first edge, we can 'drop'
750  // the current depth. For the most extreme example: if we'd copy a 1 byte
751  // prefix from a tree, there is only a single edge / path from the top of the
752  // tree to the single data edge containing this byte, so we can drop all the
753  // nodes except the data node.
754  int height = this->height();
755  CordRepBtree* node = this;
756  CordRep* front = node->Edge(kFront);
757  if (allow_folding) {
758  while (front->length >= n) {
759  if (--height < 0) return {MakeSubstring(CordRep::Ref(front), 0, n), -1};
760  node = front->btree();
761  front = node->Edge(kFront);
762  }
763  }
764  if (node->length == n) return {CordRep::Ref(node), height};
765 
766  // `n` spans at least two nodes, find the end point of the span.
767  Position pos = node->IndexOf(n);
768 
769  // Create a partial copy of the node up to `pos.index`, with a defined length
770  // of `n`. Any 'partial last edge' is added further below as needed.
771  CordRepBtree* sub = node->CopyBeginTo(pos.index, n);
772  const CopyResult result = {sub, height};
773 
774  // `pos.n` contains the 'offset inside the edge for IndexOf(n)'. As long as
775  // this is not zero, we don't have a 'clean cut', so we need to make a
776  // (partial) copy of that last edge, and repeat this until pos.n is zero.
777  while (pos.n != 0) {
778  size_t end = pos.index;
779  n = pos.n;
780 
781  CordRep* edge = node->Edge(pos.index);
782  if (--height < 0) {
783  sub->edges_[end++] = MakeSubstring(CordRep::Ref(edge), 0, n);
784  sub->set_end(end);
785  AssertValid(result.edge->btree());
786  return result;
787  }
788 
789  node = edge->btree();
790  pos = node->IndexOf(n);
791  CordRepBtree* nsub = node->CopyBeginTo(pos.index, n);
792  sub->edges_[end++] = nsub;
793  sub->set_end(end);
794  sub = nsub;
795  }
796  sub->set_end(pos.index);
797  AssertValid(result.edge->btree());
798  return result;
799 }
800 
802  CordRep* front = tree->Edge(tree->begin());
803  if (tree->refcount.IsOne()) {
804  Unref(tree->Edges(tree->begin() + 1, tree->end()));
805  CordRepBtree::Delete(tree);
806  } else {
807  CordRep::Ref(front);
808  CordRep::Unref(tree);
809  }
810  return front;
811 }
812 
814  size_t new_length) {
815  assert(end <= tree->end());
816  if (tree->refcount.IsOne()) {
817  Unref(tree->Edges(end, tree->end()));
818  tree->set_end(end);
819  tree->length = new_length;
820  } else {
821  CordRepBtree* old = tree;
822  tree = tree->CopyBeginTo(end, new_length);
824  }
825  return tree;
826 }
827 
829  // Check input and deal with trivial cases 'Remove all/none'
830  assert(tree != nullptr);
831  assert(n <= tree->length);
832  const size_t len = tree->length;
833  if (ABSL_PREDICT_FALSE(n == 0)) {
834  return tree;
835  }
836  if (ABSL_PREDICT_FALSE(n >= len)) {
837  CordRepBtree::Unref(tree);
838  return nullptr;
839  }
840 
841  size_t length = len - n;
842  int height = tree->height();
843  bool is_mutable = tree->refcount.IsOne();
844 
845  // Extract all top nodes which are reduced to size = 1
846  Position pos = tree->IndexOfLength(length);
847  while (pos.index == tree->begin()) {
848  CordRep* edge = ExtractFront(tree);
849  is_mutable &= edge->refcount.IsOne();
850  if (height-- == 0) return ResizeEdge(edge, length, is_mutable);
851  tree = edge->btree();
852  pos = tree->IndexOfLength(length);
853  }
854 
855  // Repeat the following sequence traversing down the tree:
856  // - Crop the top node to the 'last remaining edge' adjusting length.
857  // - Set the length for down edges to the partial length in that last edge.
858  // - Repeat this until the last edge is 'included in full'
859  // - If we hit the data edge level, resize and return the last data edge
860  CordRepBtree* top = tree = ConsumeBeginTo(tree, pos.index + 1, length);
861  CordRep* edge = tree->Edge(pos.index);
862  length = pos.n;
863  while (length != edge->length) {
864  // ConsumeBeginTo guarantees `tree` is a clean, privately owned copy.
865  assert(tree->refcount.IsOne());
866  const bool edge_is_mutable = edge->refcount.IsOne();
867 
868  if (height-- == 0) {
869  tree->edges_[pos.index] = ResizeEdge(edge, length, edge_is_mutable);
870  return AssertValid(top);
871  }
872 
873  if (!edge_is_mutable) {
874  // We can't 'in place' remove any suffixes down this edge.
875  // Replace this edge with a prefix copy instead.
876  tree->edges_[pos.index] = edge->btree()->CopyPrefix(length, false).edge;
877  CordRep::Unref(edge);
878  return AssertValid(top);
879  }
880 
881  // Move down one level, rinse repeat.
882  tree = edge->btree();
883  pos = tree->IndexOfLength(length);
884  tree = ConsumeBeginTo(edge->btree(), pos.index + 1, length);
885  edge = tree->Edge(pos.index);
886  length = pos.n;
887  }
888 
889  return AssertValid(top);
890 }
891 
893  assert(n <= this->length);
894  assert(offset <= this->length - n);
895  if (ABSL_PREDICT_FALSE(n == 0)) return nullptr;
896 
897  CordRepBtree* node = this;
898  int height = node->height();
899  Position front = node->IndexOf(offset);
900  CordRep* left = node->edges_[front.index];
901  while (front.n + n <= left->length) {
902  if (--height < 0) return MakeSubstring(CordRep::Ref(left), front.n, n);
903  node = left->btree();
904  front = node->IndexOf(front.n);
905  left = node->edges_[front.index];
906  }
907 
908  const Position back = node->IndexBefore(front, n);
909  CordRep* const right = node->edges_[back.index];
910  assert(back.index > front.index);
911 
912  // Get partial suffix and prefix entries.
915  if (height > 0) {
916  // Copy prefix and suffix of the boundary nodes.
917  prefix = left->btree()->CopySuffix(front.n);
918  suffix = right->btree()->CopyPrefix(back.n);
919 
920  // If there is an edge between the prefix and suffix edges, then the tree
921  // must remain at its previous (full) height. If we have no edges between
922  // prefix and suffix edges, then the tree must be as high as either the
923  // suffix or prefix edges (which are collapsed to their minimum heights).
924  if (front.index + 1 == back.index) {
925  height = (std::max)(prefix.height, suffix.height) + 1;
926  }
927 
928  // Raise prefix and suffixes to the new tree height.
929  for (int h = prefix.height + 1; h < height; ++h) {
930  prefix.edge = CordRepBtree::New(prefix.edge);
931  }
932  for (int h = suffix.height + 1; h < height; ++h) {
933  suffix.edge = CordRepBtree::New(suffix.edge);
934  }
935  } else {
936  // Leaf node, simply take substrings for prefix and suffix.
937  prefix = CopyResult{MakeSubstring(CordRep::Ref(left), front.n), -1};
938  suffix = CopyResult{MakeSubstring(CordRep::Ref(right), 0, back.n), -1};
939  }
940 
941  // Compose resulting tree.
943  size_t end = 0;
944  sub->edges_[end++] = prefix.edge;
945  for (CordRep* r : node->Edges(front.index + 1, back.index)) {
946  sub->edges_[end++] = CordRep::Ref(r);
947  }
948  sub->edges_[end++] = suffix.edge;
949  sub->set_end(end);
950  sub->length = n;
951  return AssertValid(sub);
952 }
953 
955  CordRepBtree* right) {
956  return left->height() >= right->height() ? Merge<kBack>(left, right)
957  : Merge<kFront>(right, left);
958 }
959 
961  if (height() == 0 && size() == 1) {
962  if (fragment) *fragment = Data(begin());
963  return true;
964  }
965  return false;
966 }
967 
968 bool CordRepBtree::IsFlat(size_t offset, const size_t n,
969  absl::string_view* fragment) const {
970  assert(n <= this->length);
971  assert(offset <= this->length - n);
972  if (ABSL_PREDICT_FALSE(n == 0)) return false;
973  int height = this->height();
974  const CordRepBtree* node = this;
975  for (;;) {
976  const Position front = node->IndexOf(offset);
977  const CordRep* edge = node->Edge(front.index);
978  if (edge->length < front.n + n) return false;
979  if (--height < 0) {
980  if (fragment) *fragment = EdgeData(edge).substr(front.n, n);
981  return true;
982  }
983  offset = front.n;
984  node = node->Edge(front.index)->btree();
985  }
986 }
987 
988 char CordRepBtree::GetCharacter(size_t offset) const {
989  assert(offset < length);
990  const CordRepBtree* node = this;
991  int height = node->height();
992  for (;;) {
993  Position front = node->IndexOf(offset);
994  if (--height < 0) return node->Data(front.index)[front.n];
995  offset = front.n;
996  node = node->Edge(front.index)->btree();
997  }
998 }
999 
1001  // The inlined version in `GetAppendBuffer()` deals with all heights <= 3.
1002  assert(height() >= 4);
1003  assert(refcount.IsOne());
1004 
1005  // Build a stack of nodes we may potentially need to update if we find a
1006  // non-shared FLAT with capacity at the leaf level.
1007  const int depth = height();
1008  CordRepBtree* node = this;
1010  for (int i = 0; i < depth; ++i) {
1011  node = node->Edge(kBack)->btree();
1012  if (!node->refcount.IsOne()) return {};
1013  stack[i] = node;
1014  }
1015 
1016  // Must be a privately owned, mutable flat.
1017  CordRep* const edge = node->Edge(kBack);
1018  if (!edge->refcount.IsOne() || edge->tag < FLAT) return {};
1019 
1020  // Must have capacity.
1021  const size_t avail = edge->flat()->Capacity() - edge->length;
1022  if (avail == 0) return {};
1023 
1024  // Build span on remaining capacity.
1025  size_t delta = (std::min)(size, avail);
1026  Span<char> span = {edge->flat()->Data() + edge->length, delta};
1027  edge->length += delta;
1028  this->length += delta;
1029  for (int i = 0; i < depth; ++i) {
1030  stack[i]->length += delta;
1031  }
1032  return span;
1033 }
1034 
1036  if (rep->IsBtree()) return rep->btree();
1037 
1038  CordRepBtree* node = nullptr;
1039  auto consume = [&node](CordRep* r, size_t offset, size_t length) {
1040  r = MakeSubstring(r, offset, length);
1041  if (node == nullptr) {
1042  node = New(r);
1043  } else {
1044  node = CordRepBtree::AddCordRep<kBack>(node, r);
1045  }
1046  };
1047  Consume(rep, consume);
1048  return node;
1049 }
1050 
1052  if (ABSL_PREDICT_TRUE(rep->IsBtree())) {
1053  return MergeTrees(tree, rep->btree());
1054  }
1055  auto consume = [&tree](CordRep* r, size_t offset, size_t length) {
1056  r = MakeSubstring(r, offset, length);
1057  tree = CordRepBtree::AddCordRep<kBack>(tree, r);
1058  };
1059  Consume(rep, consume);
1060  return tree;
1061 }
1062 
1064  if (ABSL_PREDICT_TRUE(rep->IsBtree())) {
1065  return MergeTrees(rep->btree(), tree);
1066  }
1067  auto consume = [&tree](CordRep* r, size_t offset, size_t length) {
1068  r = MakeSubstring(r, offset, length);
1069  tree = CordRepBtree::AddCordRep<kFront>(tree, r);
1070  };
1071  ReverseConsume(rep, consume);
1072  return tree;
1073 }
1074 
1076  size_t extra) {
1077  return CordRepBtree::AddData<kBack>(tree, data, extra);
1078 }
1079 
1081  size_t extra) {
1082  return CordRepBtree::AddData<kFront>(tree, data, extra);
1083 }
1084 
1085 template CordRepBtree* CordRepBtree::AddCordRep<kFront>(CordRepBtree* tree,
1086  CordRep* rep);
1087 template CordRepBtree* CordRepBtree::AddCordRep<kBack>(CordRepBtree* tree,
1088  CordRep* rep);
1089 template CordRepBtree* CordRepBtree::AddData<kFront>(CordRepBtree* tree,
1091  size_t extra);
1092 template CordRepBtree* CordRepBtree::AddData<kBack>(CordRepBtree* tree,
1094  size_t extra);
1095 
1097  bool consume) {
1098  bool owned = consume && tree->refcount.IsOne();
1099  if (tree->height() == 0) {
1100  for (CordRep* edge : tree->Edges()) {
1101  if (!owned) edge = CordRep::Ref(edge);
1102  size_t height = 0;
1103  size_t length = edge->length;
1104  CordRepBtree* node = stack[0];
1105  OpResult result = node->AddEdge<kBack>(true, edge, length);
1106  while (result.action == CordRepBtree::kPopped) {
1107  stack[height] = result.tree;
1108  if (stack[++height] == nullptr) {
1109  result.action = CordRepBtree::kSelf;
1110  stack[height] = CordRepBtree::New(node, result.tree);
1111  } else {
1112  node = stack[height];
1113  result = node->AddEdge<kBack>(true, result.tree, length);
1114  }
1115  }
1116  while (stack[++height] != nullptr) {
1117  stack[height]->length += length;
1118  }
1119  }
1120  } else {
1121  for (CordRep* rep : tree->Edges()) {
1122  Rebuild(stack, rep->btree(), owned);
1123  }
1124  }
1125  if (consume) {
1126  if (owned) {
1127  CordRepBtree::Delete(tree);
1128  } else {
1129  CordRepBtree::Unref(tree);
1130  }
1131  }
1132 }
1133 
1135  // Set up initial stack with empty leaf node.
1136  CordRepBtree* node = CordRepBtree::New();
1138 
1139  // Recursively build the tree, consuming the input tree.
1140  Rebuild(stack, tree, /* consume reference */ true);
1141 
1142  // Return top most node
1143  for (CordRepBtree* parent : stack) {
1144  if (parent == nullptr) return node;
1145  node = parent;
1146  }
1147 
1148  // Unreachable
1149  assert(false);
1150  return nullptr;
1151 }
1152 
1154  CordRepBtree* tree, size_t extra_capacity) {
1155  int depth = 0;
1156  NodeStack stack;
1157 
1158  // Set up default 'no success' result which is {tree, nullptr}.
1160  result.tree = tree;
1161  result.extracted = nullptr;
1162 
1163  // Dive down the right side of the tree, making sure no edges are shared.
1164  while (tree->height() > 0) {
1165  if (!tree->refcount.IsOne()) return result;
1166  stack[depth++] = tree;
1167  tree = tree->Edge(kBack)->btree();
1168  }
1169  if (!tree->refcount.IsOne()) return result;
1170 
1171  // Validate we ended on a non shared flat.
1172  CordRep* rep = tree->Edge(kBack);
1173  if (!(rep->IsFlat() && rep->refcount.IsOne())) return result;
1174 
1175  // Verify it has at least the requested extra capacity.
1176  CordRepFlat* flat = rep->flat();
1177  const size_t length = flat->length;
1178  const size_t avail = flat->Capacity() - flat->length;
1179  if (extra_capacity > avail) return result;
1180 
1181  // Set the extracted flat in the result.
1182  result.extracted = flat;
1183 
1184  // Cascading delete all nodes that become empty.
1185  while (tree->size() == 1) {
1186  CordRepBtree::Delete(tree);
1187  if (--depth < 0) {
1188  // We consumed the entire tree: return nullptr for new tree.
1189  result.tree = nullptr;
1190  return result;
1191  }
1192  rep = tree;
1193  tree = stack[depth];
1194  }
1195 
1196  // Remove the edge or cascaded up parent node.
1197  tree->set_end(tree->end() - 1);
1198  tree->length -= length;
1199 
1200  // Adjust lengths up the tree.
1201  while (depth > 0) {
1202  tree = stack[--depth];
1203  tree->length -= length;
1204  }
1205 
1206  // Remove unnecessary top nodes with size = 1. This may iterate all the way
1207  // down to the leaf node in which case we simply return the remaining last
1208  // edge in that node and the extracted flat.
1209  while (tree->size() == 1) {
1210  int height = tree->height();
1211  rep = tree->Edge(kBack);
1212  Delete(tree);
1213  if (height == 0) {
1214  // We consumed the leaf: return the sole data edge as the new tree.
1215  result.tree = rep;
1216  return result;
1217  }
1218  tree = rep->btree();
1219  }
1220 
1221  // Done: return the (new) top level node and extracted flat.
1222  result.tree = tree;
1223  return result;
1224 }
1225 
1226 } // namespace cord_internal
1228 } // namespace absl
ABSL_PREDICT_FALSE
#define ABSL_PREDICT_FALSE(x)
Definition: abseil-cpp/absl/base/optimization.h:180
ABSL_RAW_CHECK
#define ABSL_RAW_CHECK(condition, message)
Definition: abseil-cpp/absl/base/internal/raw_logging.h:59
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
absl::cord_internal::CordRepBtree::end
size_t end() const
Definition: cord_rep_btree.h:290
absl::cord_internal::EXTERNAL
@ EXTERNAL
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:183
dst
static const char dst[]
Definition: test-fs-copyfile.c:37
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
absl::cord_internal::ReverseConsume
void ReverseConsume(CordRep *rep, ConsumeFn consume_fn)
Definition: cord_rep_consume.cc:56
absl::cord_internal::CordRepBtree::kMaxCapacity
static constexpr size_t kMaxCapacity
Definition: cord_rep_btree.h:81
cord_data_edge.h
pos
int pos
Definition: libuv/docs/code/tty-gravity/main.c:11
absl::cord_internal::CordRep::IsBtree
constexpr bool IsBtree() const
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:250
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
absl::cord_internal::CordRepBtree::CopyBeginTo
CordRepBtree * CopyBeginTo(size_t end, size_t new_length) const
Definition: cord_rep_btree.h:692
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
absl::cord_internal::CordRepBtree::Position::index
size_t index
Definition: cord_rep_btree.h:151
absl::cord_internal::CordRepBtree::PrependSlow
static CordRepBtree * PrependSlow(CordRepBtree *, CordRep *rep)
Definition: cord_rep_btree.cc:1063
absl::cord_internal::CordRep::Unref
static void Unref(CordRep *rep)
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:642
absl::cord_internal::CordRepBtree::set_end
void set_end(size_t end)
Definition: cord_rep_btree.h:387
absl::cord_internal::CordRepBtree::capacity
size_t capacity() const
Definition: cord_rep_btree.h:302
absl::cord_internal::CordRepFlat::New
static CordRepFlat * New(size_t len)
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:128
absl::cord_internal::CordRep::external
CordRepExternal * external()
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:624
absl::cord_internal::CordRepBtree::IndexBefore
Position IndexBefore(size_t offset) const
Definition: cord_rep_btree.h:795
absl::Span
Definition: abseil-cpp/absl/types/span.h:152
absl::cord_internal::CordRepFlat::Delete
static void Delete(CordRep *rep)
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:137
absl::cord_internal::Consume
void Consume(CordRep *rep, ConsumeFn consume_fn)
Definition: cord_rep_consume.cc:45
absl::cord_internal::CordRepBtree::set_begin
void set_begin(size_t begin)
Definition: cord_rep_btree.h:386
absl::cord_internal::RefcountAndFlags::Decrement
bool Decrement()
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:114
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
absl::cord_internal::CordRepFlat::Capacity
size_t Capacity() const
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:166
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::CordRepBtree::CopyToEndFrom
CordRepBtree * CopyToEndFrom(size_t begin, size_t new_length) const
Definition: cord_rep_btree.h:681
New
T * New(Args &&... args)
Definition: third_party/boringssl-with-bazel/src/ssl/internal.h:195
absl::cord_internal::CordRepBtree::IndexOf
Position IndexOf(size_t offset) const
Definition: cord_rep_btree.h:788
absl::cord_internal::CordRepBtree::Data
absl::string_view Data(size_t index) const
Definition: cord_rep_btree.h:628
absl::FormatConversionChar::s
@ s
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
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::cord_internal::CordRepBtree::Prepend
static CordRepBtree * Prepend(CordRepBtree *tree, CordRep *rep)
Definition: cord_rep_btree.h:899
absl::cord_internal::CordRepBtree::AlignEnd
void AlignEnd()
Definition: cord_rep_btree.h:729
absl::cord_internal::CordRep::ExtractResult
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:217
absl::cord_internal::CordRepBtree::AddData
absl::string_view AddData(absl::string_view data, size_t extra)
absl::cord_internal::CordRepBtree::RemoveSuffix
static CordRep * RemoveSuffix(CordRepBtree *tree, size_t n)
Definition: cord_rep_btree.cc:828
absl::cord_internal::CordRepBtree::CopyPrefix
CopyResult CopyPrefix(size_t n, bool allow_folding=true)
Definition: cord_rep_btree.cc:745
absl::cord_internal::CordRepBtree::New
static CordRepBtree * New(int height=0)
Definition: cord_rep_btree.h:633
absl::synchronization_internal::Get
static GraphId Get(const IdMap &id, int num)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles_test.cc:44
absl::cord_internal::CordRepBtree::kFront
static constexpr EdgeType kFront
Definition: cord_rep_btree.h:73
absl::cord_internal::CordRepBtree::Delete
static void Delete(CordRepBtree *tree)
Definition: cord_rep_btree.h:168
absl::cord_internal::CordRep::tag
uint8_t tag
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:232
absl::Hex
Definition: abseil-cpp/absl/strings/str_cat.h:134
absl::ABSL_NAMESPACE_BEGIN::Unwind
ABSL_ATTRIBUTE_ALWAYS_INLINE int Unwind(void **result, int *sizes, int max_depth, int skip_count, const void *uc, int *min_dropped_frames)
Definition: abseil-cpp/absl/debugging/stacktrace.cc:69
refcount
size_t refcount
Definition: abseil-cpp/absl/strings/internal/cordz_info.cc:122
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
absl::cord_internal::CordRepBtree::EdgeType
EdgeType
Definition: cord_rep_btree.h:70
absl::cord_internal::CordRepBtree::kMaxDepth
static constexpr int kMaxDepth
Definition: cord_rep_btree.h:98
absl::cord_internal::CordRepBtree::kPopped
@ kPopped
Definition: cord_rep_btree.h:130
absl::cord_internal::CordRepBtree::GetCharacter
char GetCharacter(size_t offset) const
Definition: cord_rep_btree.cc:988
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::cord_internal::CordRepBtree::Dump
static void Dump(const CordRep *rep, std::ostream &stream)
Definition: cord_rep_btree.cc:380
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
absl::cord_internal::CordRepBtree::size
size_t size() const
Definition: cord_rep_btree.h:301
absl::cord_internal::DestroyTree
static void DestroyTree(CordRepBtree *tree)
Definition: cord_rep_btree.cc:385
gen_synthetic_protos.label
label
Definition: gen_synthetic_protos.py:102
generate-asm-lcov.fn
fn
Definition: generate-asm-lcov.py:146
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
absl::cord_internal::CordRepBtree::Destroy
static void Destroy(CordRepBtree *tree)
Definition: cord_rep_btree.cc:401
absl::cord_internal::CordRep::refcount
RefcountAndFlags refcount
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:229
absl::cord_internal::CordRepBtree::SetEdge
OpResult SetEdge(bool owned, CordRep *edge, size_t delta)
Definition: cord_rep_btree.cc:491
absl::cord_internal::FLAT
@ FLAT
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:194
absl::cord_internal::CordRepBtree::begin
size_t begin() const
Definition: cord_rep_btree.h:288
absl::cord_internal::CordRep::IsFlat
constexpr bool IsFlat() const
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:249
cord_rep_btree.h
absl::cord_internal::CordRepBtree::Merge
static CordRepBtree * Merge(CordRepBtree *dst, CordRepBtree *src)
Definition: cord_rep_btree.cc:647
absl::cord_internal::CordRepBtree::IndexBeyond
Position IndexBeyond(size_t offset) const
Definition: cord_rep_btree.h:819
stack
NodeStack stack
Definition: cord_rep_btree.cc:356
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
absl::cord_internal::CordRepBtree::Position::n
size_t n
Definition: cord_rep_btree.h:152
absl::cord_internal::CordRepBtree::AlignBegin
void AlignBegin()
Definition: cord_rep_btree.h:703
absl::cord_internal::CordRepSubstring::start
size_t start
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:281
absl::cord_internal::CordRepBtree::index
size_t index(EdgeType edge) const
Definition: cord_rep_btree.h:291
absl::cord_internal::CordRepBtree::CopyRaw
CordRepBtree * CopyRaw() const
Definition: cord_rep_btree.h:668
min
#define min(a, b)
Definition: qsort.h:83
absl::cord_internal::CordRepBtree::IndexOfLength
Position IndexOfLength(size_t n) const
Definition: cord_rep_btree.h:811
share_depth
int share_depth
Definition: cord_rep_btree.cc:354
absl::cord_internal::CordRepBtree::AppendSlow
static CordRepBtree * AppendSlow(CordRepBtree *, CordRep *rep)
Definition: cord_rep_btree.cc:1051
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
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_PREDICT_TRUE
#define ABSL_PREDICT_TRUE(x)
Definition: abseil-cpp/absl/base/optimization.h:181
absl::cord_internal::CordRepBtree::AddCordRep
static CordRepBtree * AddCordRep(CordRepBtree *tree, CordRep *rep)
Definition: cord_rep_btree.cc:514
absl::cord_internal::CordRepBtree::CopySuffix
CopyResult CopySuffix(size_t offset)
Definition: cord_rep_btree.cc:686
absl::cord_internal::CordRep::length
size_t length
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:228
absl::cord_internal::CordRep::IsExternal
constexpr bool IsExternal() const
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:248
absl::cord_internal::CordRepBtree::MergeTrees
static CordRepBtree * MergeTrees(CordRepBtree *left, CordRepBtree *right)
Definition: cord_rep_btree.cc:954
absl::cord_internal::CordRepBtree::SubTree
CordRep * SubTree(size_t offset, size_t n)
Definition: cord_rep_btree.cc:892
FATAL
#define FATAL(msg)
Definition: task.h:88
absl::cord_internal::CordRepBtree::IsValid
static bool IsValid(const CordRepBtree *tree, bool shallow=false)
Definition: cord_rep_btree.cc:417
absl::cord_internal::CordRepBtree::kCopied
@ kCopied
Definition: cord_rep_btree.h:130
absl::cord_internal::CordRep::btree
CordRepBtree * btree()
Definition: cord_rep_btree.h:589
absl::cord_internal::CordRepBtree::kSelf
@ kSelf
Definition: cord_rep_btree.h:130
absl::cord_internal::CordRepBtree::CopyResult::edge
CordRep * edge
Definition: cord_rep_btree.h:143
suffix
unsigned char suffix[65536]
Definition: bloaty/third_party/zlib/examples/gun.c:164
absl::cord_internal::CordRepBtree
Definition: cord_rep_btree.h:63
absl::cord_internal::CordRepBtree::AddEdge
OpResult AddEdge(bool owned, CordRep *edge, size_t delta)
Definition: cord_rep_btree.cc:482
absl::cord_internal::CordRepBtree::Rebuild
static CordRepBtree * Rebuild(CordRepBtree *tree)
Definition: cord_rep_btree.cc:1134
ABSL_INTERNAL_UNREACHABLE
#define ABSL_INTERNAL_UNREACHABLE
Definition: abseil-cpp/absl/base/macros.h:155
absl::cord_internal::CordRepFlat::Data
char * Data()
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:162
fix_build_deps.r
r
Definition: fix_build_deps.py:491
absl::cord_internal::SUBSTRING
@ SUBSTRING
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:179
absl::cord_internal::CordRepBtree::Edge
CordRep * Edge(size_t index) const
Definition: cord_rep_btree.h:606
prefix
static const char prefix[]
Definition: head_of_line_blocking.cc:28
rep
const CordRep * rep
Definition: cord_analysis.cc:53
absl::cord_internal::CordRepBtree::Edges
absl::Span< CordRep *const > Edges() const
Definition: cord_rep_btree.h:616
absl::cord_internal::CordRep::Ref
static CordRep * Ref(CordRep *rep)
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:634
absl::cord_internal::CordRepBtree::CopyResult
Definition: cord_rep_btree.h:142
absl::cord_internal::CordRepBtree::ExtractFront
static CordRep * ExtractFront(CordRepBtree *tree)
Definition: cord_rep_btree.cc:801
absl::cord_internal::CordRepBtree::AssertValid
static CordRepBtree * AssertValid(CordRepBtree *tree, bool shallow=true)
Definition: cord_rep_btree.cc:462
absl::cord_internal::CordRepBtree::ConsumeBeginTo
static CordRepBtree * ConsumeBeginTo(CordRepBtree *tree, size_t end, size_t new_length)
Definition: cord_rep_btree.cc:813
absl::cord_internal::CordRepBtree::sub_fetch_begin
size_t sub_fetch_begin(size_t n)
Definition: cord_rep_btree.h:392
absl::cord_internal::CordRepExternal::Delete
static void Delete(CordRep *rep)
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:401
absl::cord_internal::CordRepBtree::Position
Definition: cord_rep_btree.h:150
absl::cord_internal::IsDataEdge
bool IsDataEdge(const CordRep *edge)
Definition: cord_data_edge.h:32
absl::cord_internal::CordRepBtree::OpResult
Definition: cord_rep_btree.h:133
absl::cord_internal::CordRepBtree::back
size_t back() const
Definition: cord_rep_btree.h:289
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::cord_internal::CordRepBtree::height
int height() const
Definition: cord_rep_btree.h:285
NODE_CHECK_EQ
#define NODE_CHECK_EQ(x, y)
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
cord_rep_consume.h
absl::cord_internal::CordRepBtree::kBack
static constexpr EdgeType kBack
Definition: cord_rep_btree.h:74
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
length
std::size_t length
Definition: abseil-cpp/absl/time/internal/test_util.cc:57
mkowners.depth
depth
Definition: mkowners.py:114
ABSL_FALLTHROUGH_INTENDED
#define ABSL_FALLTHROUGH_INTENDED
Definition: abseil-cpp/absl/base/attributes.h:641
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
ops
static grpc_op ops[6]
Definition: test/core/fling/client.cc:39
Fn
void Fn()
ABSL_RAW_LOG
#define ABSL_RAW_LOG(severity,...)
Definition: abseil-cpp/absl/base/internal/raw_logging.h:44
absl::cord_internal::RefcountAndFlags::IsOne
bool IsOne()
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:144
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
binary_size.old
string old
Definition: binary_size.py:128
absl::cord_internal::CordRepFlat
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:107
top
static upb_pb_encoder_segment * top(upb_pb_encoder *e)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:7624
absl::cord_internal::CordRepBtree::fetch_add_end
size_t fetch_add_end(size_t n)
Definition: cord_rep_btree.h:399
absl::cord_internal::CordRep::substring
CordRepSubstring * substring()
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:614
NODE_CHECK_VALID
#define NODE_CHECK_VALID(x)
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
absl::cord_internal::CordRepBtree::CreateSlow
static CordRepBtree * CreateSlow(CordRep *rep)
Definition: cord_rep_btree.cc:1035
offset
voidpf uLong offset
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:142
owned
bool owned
Definition: src/php/ext/grpc/call.h:31
absl::cord_internal::CordRepBtree::GetAppendBufferSlow
Span< char > GetAppendBufferSlow(size_t size)
Definition: cord_rep_btree.cc:1000
height
int height
Definition: libuv/docs/code/tty-gravity/main.c:10
absl::cord_internal::CordRepBtree::ToOpResult
OpResult ToOpResult(bool owned)
Definition: cord_rep_btree.h:784
absl::cord_internal::CordRep::flat
CordRepFlat * flat()
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:173
stream
voidpf stream
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136


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