xref: /llvm-project/llvm/lib/Support/RewriteRope.cpp (revision 0d150db214e2aa13a825b563c7238e1243d61db1)
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