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