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