summaryrefslogtreecommitdiff
path: root/absl/strings/internal/cord_rep_btree.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/internal/cord_rep_btree.cc')
-rw-r--r--absl/strings/internal/cord_rep_btree.cc71
1 files changed, 48 insertions, 23 deletions
diff --git a/absl/strings/internal/cord_rep_btree.cc b/absl/strings/internal/cord_rep_btree.cc
index 7cefcc52..83cdd5f4 100644
--- a/absl/strings/internal/cord_rep_btree.cc
+++ b/absl/strings/internal/cord_rep_btree.cc
@@ -190,24 +190,29 @@ inline void FastUnref(R* r, Fn&& fn) {
}
}
-// Deletes a leaf node data edge. Requires `rep` to be an EXTERNAL or FLAT
-// node, or a SUBSTRING of an EXTERNAL or FLAT node.
-void DeleteLeafEdge(CordRep* rep) {
- for (;;) {
+
+void DeleteSubstring(CordRepSubstring* substring) {
+ CordRep* rep = substring->child;
+ if (!rep->refcount.Decrement()) {
if (rep->tag >= FLAT) {
CordRepFlat::Delete(rep->flat());
- return;
- }
- if (rep->tag == EXTERNAL) {
+ } else {
+ assert(rep->tag == EXTERNAL);
CordRepExternal::Delete(rep->external());
- return;
}
- assert(rep->tag == SUBSTRING);
- CordRepSubstring* substring = rep->substring();
- rep = substring->child;
- assert(rep->tag == EXTERNAL || rep->tag >= FLAT);
- delete substring;
- if (rep->refcount.Decrement()) return;
+ }
+ delete substring;
+}
+
+// Deletes a leaf node data edge. Requires `IsDataEdge(rep)`.
+void DeleteLeafEdge(CordRep* rep) {
+ assert(CordRepBtree::IsDataEdge(rep));
+ if (rep->tag >= FLAT) {
+ CordRepFlat::Delete(rep->flat());
+ } else if (rep->tag == EXTERNAL) {
+ CordRepExternal::Delete(rep->external());
+ } else {
+ DeleteSubstring(rep->substring());
}
}
@@ -372,19 +377,39 @@ void CordRepBtree::Dump(const CordRep* rep, std::ostream& stream) {
Dump(rep, absl::string_view(), false, stream);
}
-void CordRepBtree::DestroyLeaf(CordRepBtree* tree, size_t begin, size_t end) {
- for (CordRep* edge : tree->Edges(begin, end)) {
- FastUnref(edge, DeleteLeafEdge);
+template <size_t size>
+static void DestroyTree(CordRepBtree* tree) {
+ for (CordRep* node : tree->Edges()) {
+ if (!node->refcount.Decrement()) {
+ for (CordRep* edge : node->btree()->Edges()) {
+ if (!edge->refcount.Decrement()) {
+ if (size == 1) {
+ DeleteLeafEdge(edge);
+ } else {
+ CordRepBtree::Destroy(edge->btree());
+ }
+ }
+ }
+ CordRepBtree::Delete(node->btree());
+ }
}
- Delete(tree);
+ CordRepBtree::Delete(tree);
}
-void CordRepBtree::DestroyNonLeaf(CordRepBtree* tree, size_t begin,
- size_t end) {
- for (CordRep* edge : tree->Edges(begin, end)) {
- FastUnref(edge->btree(), Destroy);
+void CordRepBtree::Destroy(CordRepBtree* tree) {
+ switch (tree->height()) {
+ case 0:
+ for (CordRep* edge : tree->Edges()) {
+ if (!edge->refcount.Decrement()) {
+ DeleteLeafEdge(edge);
+ }
+ }
+ return CordRepBtree::Delete(tree);
+ case 1:
+ return DestroyTree<1>(tree);
+ default:
+ return DestroyTree<2>(tree);
}
- Delete(tree);
}
bool CordRepBtree::IsValid(const CordRepBtree* tree, bool shallow) {