1*0d150db2SJacques Pienaar //===- RewriteRope.cpp - Rope specialized for rewriter --------------------===// 2*0d150db2SJacques Pienaar // 3*0d150db2SJacques Pienaar // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0d150db2SJacques Pienaar // See https://llvm.org/LICENSE.txt for license information. 5*0d150db2SJacques Pienaar // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0d150db2SJacques Pienaar // 7*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 8*0d150db2SJacques Pienaar // 9*0d150db2SJacques Pienaar // This file implements the RewriteRope class, which is a powerful string. 10*0d150db2SJacques Pienaar // 11*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 12*0d150db2SJacques Pienaar 13*0d150db2SJacques Pienaar #include "llvm/ADT/RewriteRope.h" 14*0d150db2SJacques Pienaar #include "llvm/Support/Casting.h" 15*0d150db2SJacques Pienaar #include <algorithm> 16*0d150db2SJacques Pienaar #include <cassert> 17*0d150db2SJacques Pienaar #include <cstring> 18*0d150db2SJacques Pienaar 19*0d150db2SJacques Pienaar using namespace llvm; 20*0d150db2SJacques Pienaar 21*0d150db2SJacques Pienaar /// RewriteRope is a "strong" string class, designed to make insertions and 22*0d150db2SJacques Pienaar /// deletions in the middle of the string nearly constant time (really, they are 23*0d150db2SJacques Pienaar /// O(log N), but with a very low constant factor). 24*0d150db2SJacques Pienaar /// 25*0d150db2SJacques Pienaar /// The implementation of this datastructure is a conceptual linear sequence of 26*0d150db2SJacques Pienaar /// RopePiece elements. Each RopePiece represents a view on a separately 27*0d150db2SJacques Pienaar /// allocated and reference counted string. This means that splitting a very 28*0d150db2SJacques Pienaar /// long string can be done in constant time by splitting a RopePiece that 29*0d150db2SJacques Pienaar /// references the whole string into two rope pieces that reference each half. 30*0d150db2SJacques Pienaar /// Once split, another string can be inserted in between the two halves by 31*0d150db2SJacques Pienaar /// inserting a RopePiece in between the two others. All of this is very 32*0d150db2SJacques Pienaar /// inexpensive: it takes time proportional to the number of RopePieces, not the 33*0d150db2SJacques Pienaar /// length of the strings they represent. 34*0d150db2SJacques Pienaar /// 35*0d150db2SJacques Pienaar /// While a linear sequences of RopePieces is the conceptual model, the actual 36*0d150db2SJacques Pienaar /// implementation captures them in an adapted B+ Tree. Using a B+ tree (which 37*0d150db2SJacques Pienaar /// is a tree that keeps the values in the leaves and has where each node 38*0d150db2SJacques Pienaar /// contains a reasonable number of pointers to children/values) allows us to 39*0d150db2SJacques Pienaar /// maintain efficient operation when the RewriteRope contains a *huge* number 40*0d150db2SJacques Pienaar /// of RopePieces. The basic idea of the B+ Tree is that it allows us to find 41*0d150db2SJacques Pienaar /// the RopePiece corresponding to some offset very efficiently, and it 42*0d150db2SJacques Pienaar /// automatically balances itself on insertions of RopePieces (which can happen 43*0d150db2SJacques Pienaar /// for both insertions and erases of string ranges). 44*0d150db2SJacques Pienaar /// 45*0d150db2SJacques Pienaar /// The one wrinkle on the theory is that we don't attempt to keep the tree 46*0d150db2SJacques Pienaar /// properly balanced when erases happen. Erases of string data can both insert 47*0d150db2SJacques Pienaar /// new RopePieces (e.g. when the middle of some other rope piece is deleted, 48*0d150db2SJacques Pienaar /// which results in two rope pieces, which is just like an insert) or it can 49*0d150db2SJacques Pienaar /// reduce the number of RopePieces maintained by the B+Tree. In the case when 50*0d150db2SJacques Pienaar /// the number of RopePieces is reduced, we don't attempt to maintain the 51*0d150db2SJacques Pienaar /// standard 'invariant' that each node in the tree contains at least 52*0d150db2SJacques Pienaar /// 'WidthFactor' children/values. For our use cases, this doesn't seem to 53*0d150db2SJacques Pienaar /// matter. 54*0d150db2SJacques Pienaar /// 55*0d150db2SJacques Pienaar /// The implementation below is primarily implemented in terms of three classes: 56*0d150db2SJacques Pienaar /// RopePieceBTreeNode - Common base class for: 57*0d150db2SJacques Pienaar /// 58*0d150db2SJacques Pienaar /// RopePieceBTreeLeaf - Directly manages up to '2*WidthFactor' RopePiece 59*0d150db2SJacques Pienaar /// nodes. This directly represents a chunk of the string with those 60*0d150db2SJacques Pienaar /// RopePieces concatenated. 61*0d150db2SJacques Pienaar /// RopePieceBTreeInterior - An interior node in the B+ Tree, which manages 62*0d150db2SJacques Pienaar /// up to '2*WidthFactor' other nodes in the tree. 63*0d150db2SJacques Pienaar 64*0d150db2SJacques Pienaar namespace { 65*0d150db2SJacques Pienaar 66*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 67*0d150db2SJacques Pienaar // RopePieceBTreeNode Class 68*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 69*0d150db2SJacques Pienaar 70*0d150db2SJacques Pienaar /// RopePieceBTreeNode - Common base class of RopePieceBTreeLeaf and 71*0d150db2SJacques Pienaar /// RopePieceBTreeInterior. This provides some 'virtual' dispatching methods 72*0d150db2SJacques Pienaar /// and a flag that determines which subclass the instance is. Also 73*0d150db2SJacques Pienaar /// important, this node knows the full extend of the node, including any 74*0d150db2SJacques Pienaar /// children that it has. This allows efficient skipping over entire subtrees 75*0d150db2SJacques Pienaar /// when looking for an offset in the BTree. 76*0d150db2SJacques Pienaar class RopePieceBTreeNode { 77*0d150db2SJacques Pienaar protected: 78*0d150db2SJacques Pienaar /// WidthFactor - This controls the number of K/V slots held in the BTree: 79*0d150db2SJacques Pienaar /// how wide it is. Each level of the BTree is guaranteed to have at least 80*0d150db2SJacques Pienaar /// 'WidthFactor' elements in it (either ropepieces or children), (except 81*0d150db2SJacques Pienaar /// the root, which may have less) and may have at most 2*WidthFactor 82*0d150db2SJacques Pienaar /// elements. 83*0d150db2SJacques Pienaar enum { WidthFactor = 8 }; 84*0d150db2SJacques Pienaar 85*0d150db2SJacques Pienaar /// Size - This is the number of bytes of file this node (including any 86*0d150db2SJacques Pienaar /// potential children) covers. 87*0d150db2SJacques Pienaar unsigned Size = 0; 88*0d150db2SJacques Pienaar 89*0d150db2SJacques Pienaar /// IsLeaf - True if this is an instance of RopePieceBTreeLeaf, false if it 90*0d150db2SJacques Pienaar /// is an instance of RopePieceBTreeInterior. 91*0d150db2SJacques Pienaar bool IsLeaf; 92*0d150db2SJacques Pienaar 93*0d150db2SJacques Pienaar RopePieceBTreeNode(bool isLeaf) : IsLeaf(isLeaf) {} 94*0d150db2SJacques Pienaar ~RopePieceBTreeNode() = default; 95*0d150db2SJacques Pienaar 96*0d150db2SJacques Pienaar public: 97*0d150db2SJacques Pienaar bool isLeaf() const { return IsLeaf; } 98*0d150db2SJacques Pienaar unsigned size() const { return Size; } 99*0d150db2SJacques Pienaar 100*0d150db2SJacques Pienaar void Destroy(); 101*0d150db2SJacques Pienaar 102*0d150db2SJacques Pienaar /// split - Split the range containing the specified offset so that we are 103*0d150db2SJacques Pienaar /// guaranteed that there is a place to do an insertion at the specified 104*0d150db2SJacques Pienaar /// offset. The offset is relative, so "0" is the start of the node. 105*0d150db2SJacques Pienaar /// 106*0d150db2SJacques Pienaar /// If there is no space in this subtree for the extra piece, the extra tree 107*0d150db2SJacques Pienaar /// node is returned and must be inserted into a parent. 108*0d150db2SJacques Pienaar RopePieceBTreeNode *split(unsigned Offset); 109*0d150db2SJacques Pienaar 110*0d150db2SJacques Pienaar /// insert - Insert the specified ropepiece into this tree node at the 111*0d150db2SJacques Pienaar /// specified offset. The offset is relative, so "0" is the start of the 112*0d150db2SJacques Pienaar /// node. 113*0d150db2SJacques Pienaar /// 114*0d150db2SJacques Pienaar /// If there is no space in this subtree for the extra piece, the extra tree 115*0d150db2SJacques Pienaar /// node is returned and must be inserted into a parent. 116*0d150db2SJacques Pienaar RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R); 117*0d150db2SJacques Pienaar 118*0d150db2SJacques Pienaar /// erase - Remove NumBytes from this node at the specified offset. We are 119*0d150db2SJacques Pienaar /// guaranteed that there is a split at Offset. 120*0d150db2SJacques Pienaar void erase(unsigned Offset, unsigned NumBytes); 121*0d150db2SJacques Pienaar }; 122*0d150db2SJacques Pienaar 123*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 124*0d150db2SJacques Pienaar // RopePieceBTreeLeaf Class 125*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 126*0d150db2SJacques Pienaar 127*0d150db2SJacques Pienaar /// RopePieceBTreeLeaf - Directly manages up to '2*WidthFactor' RopePiece 128*0d150db2SJacques Pienaar /// nodes. This directly represents a chunk of the string with those 129*0d150db2SJacques Pienaar /// RopePieces concatenated. Since this is a B+Tree, all values (in this case 130*0d150db2SJacques Pienaar /// instances of RopePiece) are stored in leaves like this. To make iteration 131*0d150db2SJacques Pienaar /// over the leaves efficient, they maintain a singly linked list through the 132*0d150db2SJacques Pienaar /// NextLeaf field. This allows the B+Tree forward iterator to be constant 133*0d150db2SJacques Pienaar /// time for all increments. 134*0d150db2SJacques Pienaar class RopePieceBTreeLeaf : public RopePieceBTreeNode { 135*0d150db2SJacques Pienaar /// NumPieces - This holds the number of rope pieces currently active in the 136*0d150db2SJacques Pienaar /// Pieces array. 137*0d150db2SJacques Pienaar unsigned char NumPieces = 0; 138*0d150db2SJacques Pienaar 139*0d150db2SJacques Pienaar /// Pieces - This tracks the file chunks currently in this leaf. 140*0d150db2SJacques Pienaar RopePiece Pieces[2 * WidthFactor]; 141*0d150db2SJacques Pienaar 142*0d150db2SJacques Pienaar /// NextLeaf - This is a pointer to the next leaf in the tree, allowing 143*0d150db2SJacques Pienaar /// efficient in-order forward iteration of the tree without traversal. 144*0d150db2SJacques Pienaar RopePieceBTreeLeaf **PrevLeaf = nullptr; 145*0d150db2SJacques Pienaar RopePieceBTreeLeaf *NextLeaf = nullptr; 146*0d150db2SJacques Pienaar 147*0d150db2SJacques Pienaar public: 148*0d150db2SJacques Pienaar RopePieceBTreeLeaf() : RopePieceBTreeNode(true) {} 149*0d150db2SJacques Pienaar 150*0d150db2SJacques Pienaar ~RopePieceBTreeLeaf() { 151*0d150db2SJacques Pienaar if (PrevLeaf || NextLeaf) 152*0d150db2SJacques Pienaar removeFromLeafInOrder(); 153*0d150db2SJacques Pienaar clear(); 154*0d150db2SJacques Pienaar } 155*0d150db2SJacques Pienaar 156*0d150db2SJacques Pienaar bool isFull() const { return NumPieces == 2 * WidthFactor; } 157*0d150db2SJacques Pienaar 158*0d150db2SJacques Pienaar /// clear - Remove all rope pieces from this leaf. 159*0d150db2SJacques Pienaar void clear() { 160*0d150db2SJacques Pienaar while (NumPieces) 161*0d150db2SJacques Pienaar Pieces[--NumPieces] = RopePiece(); 162*0d150db2SJacques Pienaar Size = 0; 163*0d150db2SJacques Pienaar } 164*0d150db2SJacques Pienaar 165*0d150db2SJacques Pienaar unsigned getNumPieces() const { return NumPieces; } 166*0d150db2SJacques Pienaar 167*0d150db2SJacques Pienaar const RopePiece &getPiece(unsigned i) const { 168*0d150db2SJacques Pienaar assert(i < getNumPieces() && "Invalid piece ID"); 169*0d150db2SJacques Pienaar return Pieces[i]; 170*0d150db2SJacques Pienaar } 171*0d150db2SJacques Pienaar 172*0d150db2SJacques Pienaar const RopePieceBTreeLeaf *getNextLeafInOrder() const { return NextLeaf; } 173*0d150db2SJacques Pienaar 174*0d150db2SJacques Pienaar void insertAfterLeafInOrder(RopePieceBTreeLeaf *Node) { 175*0d150db2SJacques Pienaar assert(!PrevLeaf && !NextLeaf && "Already in ordering"); 176*0d150db2SJacques Pienaar 177*0d150db2SJacques Pienaar NextLeaf = Node->NextLeaf; 178*0d150db2SJacques Pienaar if (NextLeaf) 179*0d150db2SJacques Pienaar NextLeaf->PrevLeaf = &NextLeaf; 180*0d150db2SJacques Pienaar PrevLeaf = &Node->NextLeaf; 181*0d150db2SJacques Pienaar Node->NextLeaf = this; 182*0d150db2SJacques Pienaar } 183*0d150db2SJacques Pienaar 184*0d150db2SJacques Pienaar void removeFromLeafInOrder() { 185*0d150db2SJacques Pienaar if (PrevLeaf) { 186*0d150db2SJacques Pienaar *PrevLeaf = NextLeaf; 187*0d150db2SJacques Pienaar if (NextLeaf) 188*0d150db2SJacques Pienaar NextLeaf->PrevLeaf = PrevLeaf; 189*0d150db2SJacques Pienaar } else if (NextLeaf) { 190*0d150db2SJacques Pienaar NextLeaf->PrevLeaf = nullptr; 191*0d150db2SJacques Pienaar } 192*0d150db2SJacques Pienaar } 193*0d150db2SJacques Pienaar 194*0d150db2SJacques Pienaar /// FullRecomputeSizeLocally - This method recomputes the 'Size' field by 195*0d150db2SJacques Pienaar /// summing the size of all RopePieces. 196*0d150db2SJacques Pienaar void FullRecomputeSizeLocally() { 197*0d150db2SJacques Pienaar Size = 0; 198*0d150db2SJacques Pienaar for (unsigned i = 0, e = getNumPieces(); i != e; ++i) 199*0d150db2SJacques Pienaar Size += getPiece(i).size(); 200*0d150db2SJacques Pienaar } 201*0d150db2SJacques Pienaar 202*0d150db2SJacques Pienaar /// split - Split the range containing the specified offset so that we are 203*0d150db2SJacques Pienaar /// guaranteed that there is a place to do an insertion at the specified 204*0d150db2SJacques Pienaar /// offset. The offset is relative, so "0" is the start of the node. 205*0d150db2SJacques Pienaar /// 206*0d150db2SJacques Pienaar /// If there is no space in this subtree for the extra piece, the extra tree 207*0d150db2SJacques Pienaar /// node is returned and must be inserted into a parent. 208*0d150db2SJacques Pienaar RopePieceBTreeNode *split(unsigned Offset); 209*0d150db2SJacques Pienaar 210*0d150db2SJacques Pienaar /// insert - Insert the specified ropepiece into this tree node at the 211*0d150db2SJacques Pienaar /// specified offset. The offset is relative, so "0" is the start of the 212*0d150db2SJacques Pienaar /// node. 213*0d150db2SJacques Pienaar /// 214*0d150db2SJacques Pienaar /// If there is no space in this subtree for the extra piece, the extra tree 215*0d150db2SJacques Pienaar /// node is returned and must be inserted into a parent. 216*0d150db2SJacques Pienaar RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R); 217*0d150db2SJacques Pienaar 218*0d150db2SJacques Pienaar /// erase - Remove NumBytes from this node at the specified offset. We are 219*0d150db2SJacques Pienaar /// guaranteed that there is a split at Offset. 220*0d150db2SJacques Pienaar void erase(unsigned Offset, unsigned NumBytes); 221*0d150db2SJacques Pienaar 222*0d150db2SJacques Pienaar static bool classof(const RopePieceBTreeNode *N) { return N->isLeaf(); } 223*0d150db2SJacques Pienaar }; 224*0d150db2SJacques Pienaar 225*0d150db2SJacques Pienaar } // namespace 226*0d150db2SJacques Pienaar 227*0d150db2SJacques Pienaar /// split - Split the range containing the specified offset so that we are 228*0d150db2SJacques Pienaar /// guaranteed that there is a place to do an insertion at the specified 229*0d150db2SJacques Pienaar /// offset. The offset is relative, so "0" is the start of the node. 230*0d150db2SJacques Pienaar /// 231*0d150db2SJacques Pienaar /// If there is no space in this subtree for the extra piece, the extra tree 232*0d150db2SJacques Pienaar /// node is returned and must be inserted into a parent. 233*0d150db2SJacques Pienaar RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) { 234*0d150db2SJacques Pienaar // Find the insertion point. We are guaranteed that there is a split at the 235*0d150db2SJacques Pienaar // specified offset so find it. 236*0d150db2SJacques Pienaar if (Offset == 0 || Offset == size()) { 237*0d150db2SJacques Pienaar // Fastpath for a common case. There is already a splitpoint at the end. 238*0d150db2SJacques Pienaar return nullptr; 239*0d150db2SJacques Pienaar } 240*0d150db2SJacques Pienaar 241*0d150db2SJacques Pienaar // Find the piece that this offset lands in. 242*0d150db2SJacques Pienaar unsigned PieceOffs = 0; 243*0d150db2SJacques Pienaar unsigned i = 0; 244*0d150db2SJacques Pienaar while (Offset >= PieceOffs + Pieces[i].size()) { 245*0d150db2SJacques Pienaar PieceOffs += Pieces[i].size(); 246*0d150db2SJacques Pienaar ++i; 247*0d150db2SJacques Pienaar } 248*0d150db2SJacques Pienaar 249*0d150db2SJacques Pienaar // If there is already a split point at the specified offset, just return 250*0d150db2SJacques Pienaar // success. 251*0d150db2SJacques Pienaar if (PieceOffs == Offset) 252*0d150db2SJacques Pienaar return nullptr; 253*0d150db2SJacques Pienaar 254*0d150db2SJacques Pienaar // Otherwise, we need to split piece 'i' at Offset-PieceOffs. Convert Offset 255*0d150db2SJacques Pienaar // to being Piece relative. 256*0d150db2SJacques Pienaar unsigned IntraPieceOffset = Offset - PieceOffs; 257*0d150db2SJacques Pienaar 258*0d150db2SJacques Pienaar // We do this by shrinking the RopePiece and then doing an insert of the tail. 259*0d150db2SJacques Pienaar RopePiece Tail(Pieces[i].StrData, Pieces[i].StartOffs + IntraPieceOffset, 260*0d150db2SJacques Pienaar Pieces[i].EndOffs); 261*0d150db2SJacques Pienaar Size -= Pieces[i].size(); 262*0d150db2SJacques Pienaar Pieces[i].EndOffs = Pieces[i].StartOffs + IntraPieceOffset; 263*0d150db2SJacques Pienaar Size += Pieces[i].size(); 264*0d150db2SJacques Pienaar 265*0d150db2SJacques Pienaar return insert(Offset, Tail); 266*0d150db2SJacques Pienaar } 267*0d150db2SJacques Pienaar 268*0d150db2SJacques Pienaar /// insert - Insert the specified RopePiece into this tree node at the 269*0d150db2SJacques Pienaar /// specified offset. The offset is relative, so "0" is the start of the node. 270*0d150db2SJacques Pienaar /// 271*0d150db2SJacques Pienaar /// If there is no space in this subtree for the extra piece, the extra tree 272*0d150db2SJacques Pienaar /// node is returned and must be inserted into a parent. 273*0d150db2SJacques Pienaar RopePieceBTreeNode *RopePieceBTreeLeaf::insert(unsigned Offset, 274*0d150db2SJacques Pienaar const RopePiece &R) { 275*0d150db2SJacques Pienaar // If this node is not full, insert the piece. 276*0d150db2SJacques Pienaar if (!isFull()) { 277*0d150db2SJacques Pienaar // Find the insertion point. We are guaranteed that there is a split at the 278*0d150db2SJacques Pienaar // specified offset so find it. 279*0d150db2SJacques Pienaar unsigned i = 0, e = getNumPieces(); 280*0d150db2SJacques Pienaar if (Offset == size()) { 281*0d150db2SJacques Pienaar // Fastpath for a common case. 282*0d150db2SJacques Pienaar i = e; 283*0d150db2SJacques Pienaar } else { 284*0d150db2SJacques Pienaar unsigned SlotOffs = 0; 285*0d150db2SJacques Pienaar for (; Offset > SlotOffs; ++i) 286*0d150db2SJacques Pienaar SlotOffs += getPiece(i).size(); 287*0d150db2SJacques Pienaar assert(SlotOffs == Offset && "Split didn't occur before insertion!"); 288*0d150db2SJacques Pienaar } 289*0d150db2SJacques Pienaar 290*0d150db2SJacques Pienaar // For an insertion into a non-full leaf node, just insert the value in 291*0d150db2SJacques Pienaar // its sorted position. This requires moving later values over. 292*0d150db2SJacques Pienaar for (; i != e; --e) 293*0d150db2SJacques Pienaar Pieces[e] = Pieces[e - 1]; 294*0d150db2SJacques Pienaar Pieces[i] = R; 295*0d150db2SJacques Pienaar ++NumPieces; 296*0d150db2SJacques Pienaar Size += R.size(); 297*0d150db2SJacques Pienaar return nullptr; 298*0d150db2SJacques Pienaar } 299*0d150db2SJacques Pienaar 300*0d150db2SJacques Pienaar // Otherwise, if this is leaf is full, split it in two halves. Since this 301*0d150db2SJacques Pienaar // node is full, it contains 2*WidthFactor values. We move the first 302*0d150db2SJacques Pienaar // 'WidthFactor' values to the LHS child (which we leave in this node) and 303*0d150db2SJacques Pienaar // move the last 'WidthFactor' values into the RHS child. 304*0d150db2SJacques Pienaar 305*0d150db2SJacques Pienaar // Create the new node. 306*0d150db2SJacques Pienaar RopePieceBTreeLeaf *NewNode = new RopePieceBTreeLeaf(); 307*0d150db2SJacques Pienaar 308*0d150db2SJacques Pienaar // Move over the last 'WidthFactor' values from here to NewNode. 309*0d150db2SJacques Pienaar std::copy(&Pieces[WidthFactor], &Pieces[2 * WidthFactor], 310*0d150db2SJacques Pienaar &NewNode->Pieces[0]); 311*0d150db2SJacques Pienaar // Replace old pieces with null RopePieces to drop refcounts. 312*0d150db2SJacques Pienaar std::fill(&Pieces[WidthFactor], &Pieces[2 * WidthFactor], RopePiece()); 313*0d150db2SJacques Pienaar 314*0d150db2SJacques Pienaar // Decrease the number of values in the two nodes. 315*0d150db2SJacques Pienaar NewNode->NumPieces = NumPieces = WidthFactor; 316*0d150db2SJacques Pienaar 317*0d150db2SJacques Pienaar // Recompute the two nodes' size. 318*0d150db2SJacques Pienaar NewNode->FullRecomputeSizeLocally(); 319*0d150db2SJacques Pienaar FullRecomputeSizeLocally(); 320*0d150db2SJacques Pienaar 321*0d150db2SJacques Pienaar // Update the list of leaves. 322*0d150db2SJacques Pienaar NewNode->insertAfterLeafInOrder(this); 323*0d150db2SJacques Pienaar 324*0d150db2SJacques Pienaar // These insertions can't fail. 325*0d150db2SJacques Pienaar if (this->size() >= Offset) 326*0d150db2SJacques Pienaar this->insert(Offset, R); 327*0d150db2SJacques Pienaar else 328*0d150db2SJacques Pienaar NewNode->insert(Offset - this->size(), R); 329*0d150db2SJacques Pienaar return NewNode; 330*0d150db2SJacques Pienaar } 331*0d150db2SJacques Pienaar 332*0d150db2SJacques Pienaar /// erase - Remove NumBytes from this node at the specified offset. We are 333*0d150db2SJacques Pienaar /// guaranteed that there is a split at Offset. 334*0d150db2SJacques Pienaar void RopePieceBTreeLeaf::erase(unsigned Offset, unsigned NumBytes) { 335*0d150db2SJacques Pienaar // Since we are guaranteed that there is a split at Offset, we start by 336*0d150db2SJacques Pienaar // finding the Piece that starts there. 337*0d150db2SJacques Pienaar unsigned PieceOffs = 0; 338*0d150db2SJacques Pienaar unsigned i = 0; 339*0d150db2SJacques Pienaar for (; Offset > PieceOffs; ++i) 340*0d150db2SJacques Pienaar PieceOffs += getPiece(i).size(); 341*0d150db2SJacques Pienaar assert(PieceOffs == Offset && "Split didn't occur before erase!"); 342*0d150db2SJacques Pienaar 343*0d150db2SJacques Pienaar unsigned StartPiece = i; 344*0d150db2SJacques Pienaar 345*0d150db2SJacques Pienaar // Figure out how many pieces completely cover 'NumBytes'. We want to remove 346*0d150db2SJacques Pienaar // all of them. 347*0d150db2SJacques Pienaar for (; Offset + NumBytes > PieceOffs + getPiece(i).size(); ++i) 348*0d150db2SJacques Pienaar PieceOffs += getPiece(i).size(); 349*0d150db2SJacques Pienaar 350*0d150db2SJacques Pienaar // If we exactly include the last one, include it in the region to delete. 351*0d150db2SJacques Pienaar if (Offset + NumBytes == PieceOffs + getPiece(i).size()) { 352*0d150db2SJacques Pienaar PieceOffs += getPiece(i).size(); 353*0d150db2SJacques Pienaar ++i; 354*0d150db2SJacques Pienaar } 355*0d150db2SJacques Pienaar 356*0d150db2SJacques Pienaar // If we completely cover some RopePieces, erase them now. 357*0d150db2SJacques Pienaar if (i != StartPiece) { 358*0d150db2SJacques Pienaar unsigned NumDeleted = i - StartPiece; 359*0d150db2SJacques Pienaar for (; i != getNumPieces(); ++i) 360*0d150db2SJacques Pienaar Pieces[i - NumDeleted] = Pieces[i]; 361*0d150db2SJacques Pienaar 362*0d150db2SJacques Pienaar // Drop references to dead rope pieces. 363*0d150db2SJacques Pienaar std::fill(&Pieces[getNumPieces() - NumDeleted], &Pieces[getNumPieces()], 364*0d150db2SJacques Pienaar RopePiece()); 365*0d150db2SJacques Pienaar NumPieces -= NumDeleted; 366*0d150db2SJacques Pienaar 367*0d150db2SJacques Pienaar unsigned CoverBytes = PieceOffs - Offset; 368*0d150db2SJacques Pienaar NumBytes -= CoverBytes; 369*0d150db2SJacques Pienaar Size -= CoverBytes; 370*0d150db2SJacques Pienaar } 371*0d150db2SJacques Pienaar 372*0d150db2SJacques Pienaar // If we completely removed some stuff, we could be done. 373*0d150db2SJacques Pienaar if (NumBytes == 0) 374*0d150db2SJacques Pienaar return; 375*0d150db2SJacques Pienaar 376*0d150db2SJacques Pienaar // Okay, now might be erasing part of some Piece. If this is the case, then 377*0d150db2SJacques Pienaar // move the start point of the piece. 378*0d150db2SJacques Pienaar assert(getPiece(StartPiece).size() > NumBytes); 379*0d150db2SJacques Pienaar Pieces[StartPiece].StartOffs += NumBytes; 380*0d150db2SJacques Pienaar 381*0d150db2SJacques Pienaar // The size of this node just shrunk by NumBytes. 382*0d150db2SJacques Pienaar Size -= NumBytes; 383*0d150db2SJacques Pienaar } 384*0d150db2SJacques Pienaar 385*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 386*0d150db2SJacques Pienaar // RopePieceBTreeInterior Class 387*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 388*0d150db2SJacques Pienaar 389*0d150db2SJacques Pienaar namespace { 390*0d150db2SJacques Pienaar 391*0d150db2SJacques Pienaar /// RopePieceBTreeInterior - This represents an interior node in the B+Tree, 392*0d150db2SJacques Pienaar /// which holds up to 2*WidthFactor pointers to child nodes. 393*0d150db2SJacques Pienaar class RopePieceBTreeInterior : public RopePieceBTreeNode { 394*0d150db2SJacques Pienaar /// NumChildren - This holds the number of children currently active in the 395*0d150db2SJacques Pienaar /// Children array. 396*0d150db2SJacques Pienaar unsigned char NumChildren = 0; 397*0d150db2SJacques Pienaar 398*0d150db2SJacques Pienaar RopePieceBTreeNode *Children[2 * WidthFactor]; 399*0d150db2SJacques Pienaar 400*0d150db2SJacques Pienaar public: 401*0d150db2SJacques Pienaar RopePieceBTreeInterior() : RopePieceBTreeNode(false) {} 402*0d150db2SJacques Pienaar 403*0d150db2SJacques Pienaar RopePieceBTreeInterior(RopePieceBTreeNode *LHS, RopePieceBTreeNode *RHS) 404*0d150db2SJacques Pienaar : RopePieceBTreeNode(false) { 405*0d150db2SJacques Pienaar Children[0] = LHS; 406*0d150db2SJacques Pienaar Children[1] = RHS; 407*0d150db2SJacques Pienaar NumChildren = 2; 408*0d150db2SJacques Pienaar Size = LHS->size() + RHS->size(); 409*0d150db2SJacques Pienaar } 410*0d150db2SJacques Pienaar 411*0d150db2SJacques Pienaar ~RopePieceBTreeInterior() { 412*0d150db2SJacques Pienaar for (unsigned i = 0, e = getNumChildren(); i != e; ++i) 413*0d150db2SJacques Pienaar Children[i]->Destroy(); 414*0d150db2SJacques Pienaar } 415*0d150db2SJacques Pienaar 416*0d150db2SJacques Pienaar bool isFull() const { return NumChildren == 2 * WidthFactor; } 417*0d150db2SJacques Pienaar 418*0d150db2SJacques Pienaar unsigned getNumChildren() const { return NumChildren; } 419*0d150db2SJacques Pienaar 420*0d150db2SJacques Pienaar const RopePieceBTreeNode *getChild(unsigned i) const { 421*0d150db2SJacques Pienaar assert(i < NumChildren && "invalid child #"); 422*0d150db2SJacques Pienaar return Children[i]; 423*0d150db2SJacques Pienaar } 424*0d150db2SJacques Pienaar 425*0d150db2SJacques Pienaar RopePieceBTreeNode *getChild(unsigned i) { 426*0d150db2SJacques Pienaar assert(i < NumChildren && "invalid child #"); 427*0d150db2SJacques Pienaar return Children[i]; 428*0d150db2SJacques Pienaar } 429*0d150db2SJacques Pienaar 430*0d150db2SJacques Pienaar /// FullRecomputeSizeLocally - Recompute the Size field of this node by 431*0d150db2SJacques Pienaar /// summing up the sizes of the child nodes. 432*0d150db2SJacques Pienaar void FullRecomputeSizeLocally() { 433*0d150db2SJacques Pienaar Size = 0; 434*0d150db2SJacques Pienaar for (unsigned i = 0, e = getNumChildren(); i != e; ++i) 435*0d150db2SJacques Pienaar Size += getChild(i)->size(); 436*0d150db2SJacques Pienaar } 437*0d150db2SJacques Pienaar 438*0d150db2SJacques Pienaar /// split - Split the range containing the specified offset so that we are 439*0d150db2SJacques Pienaar /// guaranteed that there is a place to do an insertion at the specified 440*0d150db2SJacques Pienaar /// offset. The offset is relative, so "0" is the start of the node. 441*0d150db2SJacques Pienaar /// 442*0d150db2SJacques Pienaar /// If there is no space in this subtree for the extra piece, the extra tree 443*0d150db2SJacques Pienaar /// node is returned and must be inserted into a parent. 444*0d150db2SJacques Pienaar RopePieceBTreeNode *split(unsigned Offset); 445*0d150db2SJacques Pienaar 446*0d150db2SJacques Pienaar /// insert - Insert the specified ropepiece into this tree node at the 447*0d150db2SJacques Pienaar /// specified offset. The offset is relative, so "0" is the start of the 448*0d150db2SJacques Pienaar /// node. 449*0d150db2SJacques Pienaar /// 450*0d150db2SJacques Pienaar /// If there is no space in this subtree for the extra piece, the extra tree 451*0d150db2SJacques Pienaar /// node is returned and must be inserted into a parent. 452*0d150db2SJacques Pienaar RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R); 453*0d150db2SJacques Pienaar 454*0d150db2SJacques Pienaar /// HandleChildPiece - A child propagated an insertion result up to us. 455*0d150db2SJacques Pienaar /// Insert the new child, and/or propagate the result further up the tree. 456*0d150db2SJacques Pienaar RopePieceBTreeNode *HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS); 457*0d150db2SJacques Pienaar 458*0d150db2SJacques Pienaar /// erase - Remove NumBytes from this node at the specified offset. We are 459*0d150db2SJacques Pienaar /// guaranteed that there is a split at Offset. 460*0d150db2SJacques Pienaar void erase(unsigned Offset, unsigned NumBytes); 461*0d150db2SJacques Pienaar 462*0d150db2SJacques Pienaar static bool classof(const RopePieceBTreeNode *N) { return !N->isLeaf(); } 463*0d150db2SJacques Pienaar }; 464*0d150db2SJacques Pienaar 465*0d150db2SJacques Pienaar } // namespace 466*0d150db2SJacques Pienaar 467*0d150db2SJacques Pienaar /// split - Split the range containing the specified offset so that we are 468*0d150db2SJacques Pienaar /// guaranteed that there is a place to do an insertion at the specified 469*0d150db2SJacques Pienaar /// offset. The offset is relative, so "0" is the start of the node. 470*0d150db2SJacques Pienaar /// 471*0d150db2SJacques Pienaar /// If there is no space in this subtree for the extra piece, the extra tree 472*0d150db2SJacques Pienaar /// node is returned and must be inserted into a parent. 473*0d150db2SJacques Pienaar RopePieceBTreeNode *RopePieceBTreeInterior::split(unsigned Offset) { 474*0d150db2SJacques Pienaar // Figure out which child to split. 475*0d150db2SJacques Pienaar if (Offset == 0 || Offset == size()) 476*0d150db2SJacques Pienaar return nullptr; // If we have an exact offset, we're already split. 477*0d150db2SJacques Pienaar 478*0d150db2SJacques Pienaar unsigned ChildOffset = 0; 479*0d150db2SJacques Pienaar unsigned i = 0; 480*0d150db2SJacques Pienaar for (; Offset >= ChildOffset + getChild(i)->size(); ++i) 481*0d150db2SJacques Pienaar ChildOffset += getChild(i)->size(); 482*0d150db2SJacques Pienaar 483*0d150db2SJacques Pienaar // If already split there, we're done. 484*0d150db2SJacques Pienaar if (ChildOffset == Offset) 485*0d150db2SJacques Pienaar return nullptr; 486*0d150db2SJacques Pienaar 487*0d150db2SJacques Pienaar // Otherwise, recursively split the child. 488*0d150db2SJacques Pienaar if (RopePieceBTreeNode *RHS = getChild(i)->split(Offset - ChildOffset)) 489*0d150db2SJacques Pienaar return HandleChildPiece(i, RHS); 490*0d150db2SJacques Pienaar return nullptr; // Done! 491*0d150db2SJacques Pienaar } 492*0d150db2SJacques Pienaar 493*0d150db2SJacques Pienaar /// insert - Insert the specified ropepiece into this tree node at the 494*0d150db2SJacques Pienaar /// specified offset. The offset is relative, so "0" is the start of the 495*0d150db2SJacques Pienaar /// node. 496*0d150db2SJacques Pienaar /// 497*0d150db2SJacques Pienaar /// If there is no space in this subtree for the extra piece, the extra tree 498*0d150db2SJacques Pienaar /// node is returned and must be inserted into a parent. 499*0d150db2SJacques Pienaar RopePieceBTreeNode *RopePieceBTreeInterior::insert(unsigned Offset, 500*0d150db2SJacques Pienaar const RopePiece &R) { 501*0d150db2SJacques Pienaar // Find the insertion point. We are guaranteed that there is a split at the 502*0d150db2SJacques Pienaar // specified offset so find it. 503*0d150db2SJacques Pienaar unsigned i = 0, e = getNumChildren(); 504*0d150db2SJacques Pienaar 505*0d150db2SJacques Pienaar unsigned ChildOffs = 0; 506*0d150db2SJacques Pienaar if (Offset == size()) { 507*0d150db2SJacques Pienaar // Fastpath for a common case. Insert at end of last child. 508*0d150db2SJacques Pienaar i = e - 1; 509*0d150db2SJacques Pienaar ChildOffs = size() - getChild(i)->size(); 510*0d150db2SJacques Pienaar } else { 511*0d150db2SJacques Pienaar for (; Offset > ChildOffs + getChild(i)->size(); ++i) 512*0d150db2SJacques Pienaar ChildOffs += getChild(i)->size(); 513*0d150db2SJacques Pienaar } 514*0d150db2SJacques Pienaar 515*0d150db2SJacques Pienaar Size += R.size(); 516*0d150db2SJacques Pienaar 517*0d150db2SJacques Pienaar // Insert at the end of this child. 518*0d150db2SJacques Pienaar if (RopePieceBTreeNode *RHS = getChild(i)->insert(Offset - ChildOffs, R)) 519*0d150db2SJacques Pienaar return HandleChildPiece(i, RHS); 520*0d150db2SJacques Pienaar 521*0d150db2SJacques Pienaar return nullptr; 522*0d150db2SJacques Pienaar } 523*0d150db2SJacques Pienaar 524*0d150db2SJacques Pienaar /// HandleChildPiece - A child propagated an insertion result up to us. 525*0d150db2SJacques Pienaar /// Insert the new child, and/or propagate the result further up the tree. 526*0d150db2SJacques Pienaar RopePieceBTreeNode * 527*0d150db2SJacques Pienaar RopePieceBTreeInterior::HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS) { 528*0d150db2SJacques Pienaar // Otherwise the child propagated a subtree up to us as a new child. See if 529*0d150db2SJacques Pienaar // we have space for it here. 530*0d150db2SJacques Pienaar if (!isFull()) { 531*0d150db2SJacques Pienaar // Insert RHS after child 'i'. 532*0d150db2SJacques Pienaar if (i + 1 != getNumChildren()) 533*0d150db2SJacques Pienaar memmove(&Children[i + 2], &Children[i + 1], 534*0d150db2SJacques Pienaar (getNumChildren() - i - 1) * sizeof(Children[0])); 535*0d150db2SJacques Pienaar Children[i + 1] = RHS; 536*0d150db2SJacques Pienaar ++NumChildren; 537*0d150db2SJacques Pienaar return nullptr; 538*0d150db2SJacques Pienaar } 539*0d150db2SJacques Pienaar 540*0d150db2SJacques Pienaar // Okay, this node is full. Split it in half, moving WidthFactor children to 541*0d150db2SJacques Pienaar // a newly allocated interior node. 542*0d150db2SJacques Pienaar 543*0d150db2SJacques Pienaar // Create the new node. 544*0d150db2SJacques Pienaar RopePieceBTreeInterior *NewNode = new RopePieceBTreeInterior(); 545*0d150db2SJacques Pienaar 546*0d150db2SJacques Pienaar // Move over the last 'WidthFactor' values from here to NewNode. 547*0d150db2SJacques Pienaar memcpy(&NewNode->Children[0], &Children[WidthFactor], 548*0d150db2SJacques Pienaar WidthFactor * sizeof(Children[0])); 549*0d150db2SJacques Pienaar 550*0d150db2SJacques Pienaar // Decrease the number of values in the two nodes. 551*0d150db2SJacques Pienaar NewNode->NumChildren = NumChildren = WidthFactor; 552*0d150db2SJacques Pienaar 553*0d150db2SJacques Pienaar // Finally, insert the two new children in the side the can (now) hold them. 554*0d150db2SJacques Pienaar // These insertions can't fail. 555*0d150db2SJacques Pienaar if (i < WidthFactor) 556*0d150db2SJacques Pienaar this->HandleChildPiece(i, RHS); 557*0d150db2SJacques Pienaar else 558*0d150db2SJacques Pienaar NewNode->HandleChildPiece(i - WidthFactor, RHS); 559*0d150db2SJacques Pienaar 560*0d150db2SJacques Pienaar // Recompute the two nodes' size. 561*0d150db2SJacques Pienaar NewNode->FullRecomputeSizeLocally(); 562*0d150db2SJacques Pienaar FullRecomputeSizeLocally(); 563*0d150db2SJacques Pienaar return NewNode; 564*0d150db2SJacques Pienaar } 565*0d150db2SJacques Pienaar 566*0d150db2SJacques Pienaar /// erase - Remove NumBytes from this node at the specified offset. We are 567*0d150db2SJacques Pienaar /// guaranteed that there is a split at Offset. 568*0d150db2SJacques Pienaar void RopePieceBTreeInterior::erase(unsigned Offset, unsigned NumBytes) { 569*0d150db2SJacques Pienaar // This will shrink this node by NumBytes. 570*0d150db2SJacques Pienaar Size -= NumBytes; 571*0d150db2SJacques Pienaar 572*0d150db2SJacques Pienaar // Find the first child that overlaps with Offset. 573*0d150db2SJacques Pienaar unsigned i = 0; 574*0d150db2SJacques Pienaar for (; Offset >= getChild(i)->size(); ++i) 575*0d150db2SJacques Pienaar Offset -= getChild(i)->size(); 576*0d150db2SJacques Pienaar 577*0d150db2SJacques Pienaar // Propagate the delete request into overlapping children, or completely 578*0d150db2SJacques Pienaar // delete the children as appropriate. 579*0d150db2SJacques Pienaar while (NumBytes) { 580*0d150db2SJacques Pienaar RopePieceBTreeNode *CurChild = getChild(i); 581*0d150db2SJacques Pienaar 582*0d150db2SJacques Pienaar // If we are deleting something contained entirely in the child, pass on the 583*0d150db2SJacques Pienaar // request. 584*0d150db2SJacques Pienaar if (Offset + NumBytes < CurChild->size()) { 585*0d150db2SJacques Pienaar CurChild->erase(Offset, NumBytes); 586*0d150db2SJacques Pienaar return; 587*0d150db2SJacques Pienaar } 588*0d150db2SJacques Pienaar 589*0d150db2SJacques Pienaar // If this deletion request starts somewhere in the middle of the child, it 590*0d150db2SJacques Pienaar // must be deleting to the end of the child. 591*0d150db2SJacques Pienaar if (Offset) { 592*0d150db2SJacques Pienaar unsigned BytesFromChild = CurChild->size() - Offset; 593*0d150db2SJacques Pienaar CurChild->erase(Offset, BytesFromChild); 594*0d150db2SJacques Pienaar NumBytes -= BytesFromChild; 595*0d150db2SJacques Pienaar // Start at the beginning of the next child. 596*0d150db2SJacques Pienaar Offset = 0; 597*0d150db2SJacques Pienaar ++i; 598*0d150db2SJacques Pienaar continue; 599*0d150db2SJacques Pienaar } 600*0d150db2SJacques Pienaar 601*0d150db2SJacques Pienaar // If the deletion request completely covers the child, delete it and move 602*0d150db2SJacques Pienaar // the rest down. 603*0d150db2SJacques Pienaar NumBytes -= CurChild->size(); 604*0d150db2SJacques Pienaar CurChild->Destroy(); 605*0d150db2SJacques Pienaar --NumChildren; 606*0d150db2SJacques Pienaar if (i != getNumChildren()) 607*0d150db2SJacques Pienaar memmove(&Children[i], &Children[i + 1], 608*0d150db2SJacques Pienaar (getNumChildren() - i) * sizeof(Children[0])); 609*0d150db2SJacques Pienaar } 610*0d150db2SJacques Pienaar } 611*0d150db2SJacques Pienaar 612*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 613*0d150db2SJacques Pienaar // RopePieceBTreeNode Implementation 614*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 615*0d150db2SJacques Pienaar 616*0d150db2SJacques Pienaar void RopePieceBTreeNode::Destroy() { 617*0d150db2SJacques Pienaar if (auto *Leaf = dyn_cast<RopePieceBTreeLeaf>(this)) 618*0d150db2SJacques Pienaar delete Leaf; 619*0d150db2SJacques Pienaar else 620*0d150db2SJacques Pienaar delete cast<RopePieceBTreeInterior>(this); 621*0d150db2SJacques Pienaar } 622*0d150db2SJacques Pienaar 623*0d150db2SJacques Pienaar /// split - Split the range containing the specified offset so that we are 624*0d150db2SJacques Pienaar /// guaranteed that there is a place to do an insertion at the specified 625*0d150db2SJacques Pienaar /// offset. The offset is relative, so "0" is the start of the node. 626*0d150db2SJacques Pienaar /// 627*0d150db2SJacques Pienaar /// If there is no space in this subtree for the extra piece, the extra tree 628*0d150db2SJacques Pienaar /// node is returned and must be inserted into a parent. 629*0d150db2SJacques Pienaar RopePieceBTreeNode *RopePieceBTreeNode::split(unsigned Offset) { 630*0d150db2SJacques Pienaar assert(Offset <= size() && "Invalid offset to split!"); 631*0d150db2SJacques Pienaar if (auto *Leaf = dyn_cast<RopePieceBTreeLeaf>(this)) 632*0d150db2SJacques Pienaar return Leaf->split(Offset); 633*0d150db2SJacques Pienaar return cast<RopePieceBTreeInterior>(this)->split(Offset); 634*0d150db2SJacques Pienaar } 635*0d150db2SJacques Pienaar 636*0d150db2SJacques Pienaar /// insert - Insert the specified ropepiece into this tree node at the 637*0d150db2SJacques Pienaar /// specified offset. The offset is relative, so "0" is the start of the 638*0d150db2SJacques Pienaar /// node. 639*0d150db2SJacques Pienaar /// 640*0d150db2SJacques Pienaar /// If there is no space in this subtree for the extra piece, the extra tree 641*0d150db2SJacques Pienaar /// node is returned and must be inserted into a parent. 642*0d150db2SJacques Pienaar RopePieceBTreeNode *RopePieceBTreeNode::insert(unsigned Offset, 643*0d150db2SJacques Pienaar const RopePiece &R) { 644*0d150db2SJacques Pienaar assert(Offset <= size() && "Invalid offset to insert!"); 645*0d150db2SJacques Pienaar if (auto *Leaf = dyn_cast<RopePieceBTreeLeaf>(this)) 646*0d150db2SJacques Pienaar return Leaf->insert(Offset, R); 647*0d150db2SJacques Pienaar return cast<RopePieceBTreeInterior>(this)->insert(Offset, R); 648*0d150db2SJacques Pienaar } 649*0d150db2SJacques Pienaar 650*0d150db2SJacques Pienaar /// erase - Remove NumBytes from this node at the specified offset. We are 651*0d150db2SJacques Pienaar /// guaranteed that there is a split at Offset. 652*0d150db2SJacques Pienaar void RopePieceBTreeNode::erase(unsigned Offset, unsigned NumBytes) { 653*0d150db2SJacques Pienaar assert(Offset + NumBytes <= size() && "Invalid offset to erase!"); 654*0d150db2SJacques Pienaar if (auto *Leaf = dyn_cast<RopePieceBTreeLeaf>(this)) 655*0d150db2SJacques Pienaar return Leaf->erase(Offset, NumBytes); 656*0d150db2SJacques Pienaar return cast<RopePieceBTreeInterior>(this)->erase(Offset, NumBytes); 657*0d150db2SJacques Pienaar } 658*0d150db2SJacques Pienaar 659*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 660*0d150db2SJacques Pienaar // RopePieceBTreeIterator Implementation 661*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 662*0d150db2SJacques Pienaar 663*0d150db2SJacques Pienaar static const RopePieceBTreeLeaf *getCN(const void *P) { 664*0d150db2SJacques Pienaar return static_cast<const RopePieceBTreeLeaf *>(P); 665*0d150db2SJacques Pienaar } 666*0d150db2SJacques Pienaar 667*0d150db2SJacques Pienaar // begin iterator. 668*0d150db2SJacques Pienaar RopePieceBTreeIterator::RopePieceBTreeIterator(const void *n) { 669*0d150db2SJacques Pienaar const auto *N = static_cast<const RopePieceBTreeNode *>(n); 670*0d150db2SJacques Pienaar 671*0d150db2SJacques Pienaar // Walk down the left side of the tree until we get to a leaf. 672*0d150db2SJacques Pienaar while (const auto *IN = dyn_cast<RopePieceBTreeInterior>(N)) 673*0d150db2SJacques Pienaar N = IN->getChild(0); 674*0d150db2SJacques Pienaar 675*0d150db2SJacques Pienaar // We must have at least one leaf. 676*0d150db2SJacques Pienaar CurNode = cast<RopePieceBTreeLeaf>(N); 677*0d150db2SJacques Pienaar 678*0d150db2SJacques Pienaar // If we found a leaf that happens to be empty, skip over it until we get 679*0d150db2SJacques Pienaar // to something full. 680*0d150db2SJacques Pienaar while (CurNode && getCN(CurNode)->getNumPieces() == 0) 681*0d150db2SJacques Pienaar CurNode = getCN(CurNode)->getNextLeafInOrder(); 682*0d150db2SJacques Pienaar 683*0d150db2SJacques Pienaar if (CurNode) 684*0d150db2SJacques Pienaar CurPiece = &getCN(CurNode)->getPiece(0); 685*0d150db2SJacques Pienaar else // Empty tree, this is an end() iterator. 686*0d150db2SJacques Pienaar CurPiece = nullptr; 687*0d150db2SJacques Pienaar CurChar = 0; 688*0d150db2SJacques Pienaar } 689*0d150db2SJacques Pienaar 690*0d150db2SJacques Pienaar void RopePieceBTreeIterator::MoveToNextPiece() { 691*0d150db2SJacques Pienaar if (CurPiece != 692*0d150db2SJacques Pienaar &getCN(CurNode)->getPiece(getCN(CurNode)->getNumPieces() - 1)) { 693*0d150db2SJacques Pienaar CurChar = 0; 694*0d150db2SJacques Pienaar ++CurPiece; 695*0d150db2SJacques Pienaar return; 696*0d150db2SJacques Pienaar } 697*0d150db2SJacques Pienaar 698*0d150db2SJacques Pienaar // Find the next non-empty leaf node. 699*0d150db2SJacques Pienaar do 700*0d150db2SJacques Pienaar CurNode = getCN(CurNode)->getNextLeafInOrder(); 701*0d150db2SJacques Pienaar while (CurNode && getCN(CurNode)->getNumPieces() == 0); 702*0d150db2SJacques Pienaar 703*0d150db2SJacques Pienaar if (CurNode) 704*0d150db2SJacques Pienaar CurPiece = &getCN(CurNode)->getPiece(0); 705*0d150db2SJacques Pienaar else // Hit end(). 706*0d150db2SJacques Pienaar CurPiece = nullptr; 707*0d150db2SJacques Pienaar CurChar = 0; 708*0d150db2SJacques Pienaar } 709*0d150db2SJacques Pienaar 710*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 711*0d150db2SJacques Pienaar // RopePieceBTree Implementation 712*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 713*0d150db2SJacques Pienaar 714*0d150db2SJacques Pienaar static RopePieceBTreeNode *getRoot(void *P) { 715*0d150db2SJacques Pienaar return static_cast<RopePieceBTreeNode *>(P); 716*0d150db2SJacques Pienaar } 717*0d150db2SJacques Pienaar 718*0d150db2SJacques Pienaar RopePieceBTree::RopePieceBTree() { Root = new RopePieceBTreeLeaf(); } 719*0d150db2SJacques Pienaar 720*0d150db2SJacques Pienaar RopePieceBTree::RopePieceBTree(const RopePieceBTree &RHS) { 721*0d150db2SJacques Pienaar assert(RHS.empty() && "Can't copy non-empty tree yet"); 722*0d150db2SJacques Pienaar Root = new RopePieceBTreeLeaf(); 723*0d150db2SJacques Pienaar } 724*0d150db2SJacques Pienaar 725*0d150db2SJacques Pienaar RopePieceBTree::~RopePieceBTree() { getRoot(Root)->Destroy(); } 726*0d150db2SJacques Pienaar 727*0d150db2SJacques Pienaar unsigned RopePieceBTree::size() const { return getRoot(Root)->size(); } 728*0d150db2SJacques Pienaar 729*0d150db2SJacques Pienaar void RopePieceBTree::clear() { 730*0d150db2SJacques Pienaar if (auto *Leaf = dyn_cast<RopePieceBTreeLeaf>(getRoot(Root))) 731*0d150db2SJacques Pienaar Leaf->clear(); 732*0d150db2SJacques Pienaar else { 733*0d150db2SJacques Pienaar getRoot(Root)->Destroy(); 734*0d150db2SJacques Pienaar Root = new RopePieceBTreeLeaf(); 735*0d150db2SJacques Pienaar } 736*0d150db2SJacques Pienaar } 737*0d150db2SJacques Pienaar 738*0d150db2SJacques Pienaar void RopePieceBTree::insert(unsigned Offset, const RopePiece &R) { 739*0d150db2SJacques Pienaar // #1. Split at Offset. 740*0d150db2SJacques Pienaar if (RopePieceBTreeNode *RHS = getRoot(Root)->split(Offset)) 741*0d150db2SJacques Pienaar Root = new RopePieceBTreeInterior(getRoot(Root), RHS); 742*0d150db2SJacques Pienaar 743*0d150db2SJacques Pienaar // #2. Do the insertion. 744*0d150db2SJacques Pienaar if (RopePieceBTreeNode *RHS = getRoot(Root)->insert(Offset, R)) 745*0d150db2SJacques Pienaar Root = new RopePieceBTreeInterior(getRoot(Root), RHS); 746*0d150db2SJacques Pienaar } 747*0d150db2SJacques Pienaar 748*0d150db2SJacques Pienaar void RopePieceBTree::erase(unsigned Offset, unsigned NumBytes) { 749*0d150db2SJacques Pienaar // #1. Split at Offset. 750*0d150db2SJacques Pienaar if (RopePieceBTreeNode *RHS = getRoot(Root)->split(Offset)) 751*0d150db2SJacques Pienaar Root = new RopePieceBTreeInterior(getRoot(Root), RHS); 752*0d150db2SJacques Pienaar 753*0d150db2SJacques Pienaar // #2. Do the erasing. 754*0d150db2SJacques Pienaar getRoot(Root)->erase(Offset, NumBytes); 755*0d150db2SJacques Pienaar } 756*0d150db2SJacques Pienaar 757*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 758*0d150db2SJacques Pienaar // RewriteRope Implementation 759*0d150db2SJacques Pienaar //===----------------------------------------------------------------------===// 760*0d150db2SJacques Pienaar 761*0d150db2SJacques Pienaar /// MakeRopeString - This copies the specified byte range into some instance of 762*0d150db2SJacques Pienaar /// RopeRefCountString, and return a RopePiece that represents it. This uses 763*0d150db2SJacques Pienaar /// the AllocBuffer object to aggregate requests for small strings into one 764*0d150db2SJacques Pienaar /// allocation instead of doing tons of tiny allocations. 765*0d150db2SJacques Pienaar RopePiece RewriteRope::MakeRopeString(const char *Start, const char *End) { 766*0d150db2SJacques Pienaar unsigned Len = End - Start; 767*0d150db2SJacques Pienaar assert(Len && "Zero length RopePiece is invalid!"); 768*0d150db2SJacques Pienaar 769*0d150db2SJacques Pienaar // If we have space for this string in the current alloc buffer, use it. 770*0d150db2SJacques Pienaar if (AllocOffs + Len <= AllocChunkSize) { 771*0d150db2SJacques Pienaar memcpy(AllocBuffer->Data + AllocOffs, Start, Len); 772*0d150db2SJacques Pienaar AllocOffs += Len; 773*0d150db2SJacques Pienaar return RopePiece(AllocBuffer, AllocOffs - Len, AllocOffs); 774*0d150db2SJacques Pienaar } 775*0d150db2SJacques Pienaar 776*0d150db2SJacques Pienaar // If we don't have enough room because this specific allocation is huge, 777*0d150db2SJacques Pienaar // just allocate a new rope piece for it alone. 778*0d150db2SJacques Pienaar if (Len > AllocChunkSize) { 779*0d150db2SJacques Pienaar unsigned Size = End - Start + sizeof(RopeRefCountString) - 1; 780*0d150db2SJacques Pienaar auto *Res = reinterpret_cast<RopeRefCountString *>(new char[Size]); 781*0d150db2SJacques Pienaar Res->RefCount = 0; 782*0d150db2SJacques Pienaar memcpy(Res->Data, Start, End - Start); 783*0d150db2SJacques Pienaar return RopePiece(Res, 0, End - Start); 784*0d150db2SJacques Pienaar } 785*0d150db2SJacques Pienaar 786*0d150db2SJacques Pienaar // Otherwise, this was a small request but we just don't have space for it 787*0d150db2SJacques Pienaar // Make a new chunk and share it with later allocations. 788*0d150db2SJacques Pienaar 789*0d150db2SJacques Pienaar unsigned AllocSize = offsetof(RopeRefCountString, Data) + AllocChunkSize; 790*0d150db2SJacques Pienaar auto *Res = reinterpret_cast<RopeRefCountString *>(new char[AllocSize]); 791*0d150db2SJacques Pienaar Res->RefCount = 0; 792*0d150db2SJacques Pienaar memcpy(Res->Data, Start, Len); 793*0d150db2SJacques Pienaar AllocBuffer = Res; 794*0d150db2SJacques Pienaar AllocOffs = Len; 795*0d150db2SJacques Pienaar 796*0d150db2SJacques Pienaar return RopePiece(AllocBuffer, 0, Len); 797*0d150db2SJacques Pienaar } 798