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