blob: 8a082edba6353b7190d590bc1f64ec593c677e58 [file] [log] [blame]
Chris Lattner5fd3e262008-04-14 17:54:23 +00001//===--- RewriteRope.cpp - Rope specialized for rewriter --------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the RewriteRope class, which is a powerful string.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Rewrite/RewriteRope.h"
15#include "llvm/Support/Casting.h"
16using namespace clang;
17using llvm::dyn_cast;
18using llvm::cast;
19
20
21//===----------------------------------------------------------------------===//
22// InsertResult Class
23//===----------------------------------------------------------------------===//
24
25/// This is an adapted B+ Tree, ... erases don't keep the tree balanced.
26
27namespace {
28 class RopePieceBTreeNode;
29 struct InsertResult {
30 RopePieceBTreeNode *LHS, *RHS;
31 };
32} // end anonymous namespace
33
34//===----------------------------------------------------------------------===//
35// RopePieceBTreeNode Class
36//===----------------------------------------------------------------------===//
37
38namespace {
39 class RopePieceBTreeNode {
40 protected:
41 /// WidthFactor - This controls the number of K/V slots held in the BTree:
42 /// how wide it is. Each level of the BTree is guaranteed to have at least
43 /// 'WidthFactor' elements in it (either ropepieces or children), (except
44 /// the root, which may have less) and may have at most 2*WidthFactor
45 /// elements.
46 enum { WidthFactor = 8 };
47
48 /// Size - This is the number of bytes of file this node (including any
49 /// potential children) covers.
50 unsigned Size;
51
52 /// IsLeaf - True if this is an instance of RopePieceBTreeLeaf, false if it
53 /// is an instance of RopePieceBTreeInterior.
54 bool IsLeaf;
55
Chris Lattnerb442e212008-04-14 20:05:32 +000056 RopePieceBTreeNode(bool isLeaf) : Size(0), IsLeaf(isLeaf) {}
Chris Lattner5fd3e262008-04-14 17:54:23 +000057 ~RopePieceBTreeNode() {}
58 public:
59
60 bool isLeaf() const { return IsLeaf; }
61 unsigned size() const { return Size; }
62
63 void Destroy();
64
65 /// split - Split the range containing the specified offset so that we are
66 /// guaranteed that there is a place to do an insertion at the specified
67 /// offset. The offset is relative, so "0" is the start of the node. This
68 /// returns true if the insertion could not be done in place, and returns
69 /// information in 'Res' about the piece that is percolated up.
70 bool split(unsigned Offset, InsertResult *Res);
71
72 /// insert - Insert the specified ropepiece into this tree node at the
73 /// specified offset. The offset is relative, so "0" is the start of the
74 /// node. This returns true if the insertion could not be done in place,
75 /// and returns information in 'Res' about the piece that is percolated up.
76 bool insert(unsigned Offset, const RopePiece &R, InsertResult *Res);
77
78 /// erase - Remove NumBytes from this node at the specified offset. We are
79 /// guaranteed that there is a split at Offset.
80 void erase(unsigned Offset, unsigned NumBytes);
81
82 static inline bool classof(const RopePieceBTreeNode *) { return true; }
83
84 };
85} // end anonymous namespace
86
87//===----------------------------------------------------------------------===//
88// RopePieceBTreeLeaf Class
89//===----------------------------------------------------------------------===//
90
91namespace {
92 class RopePieceBTreeLeaf : public RopePieceBTreeNode {
93 /// NumPieces - This holds the number of rope pieces currently active in the
94 /// Pieces array.
95 unsigned char NumPieces;
96
97 /// Pieces - This tracks the file chunks currently in this leaf.
98 ///
99 RopePiece Pieces[2*WidthFactor];
100
101 /// NextLeaf - This is a pointer to the next leaf in the tree, allowing
102 /// efficient in-order forward iteration of the tree without traversal.
103 const RopePieceBTreeLeaf *NextLeaf;
104 public:
Chris Lattner70778c82008-04-14 20:07:03 +0000105 RopePieceBTreeLeaf() : RopePieceBTreeNode(true), NumPieces(0), NextLeaf(0){}
Chris Lattner5fd3e262008-04-14 17:54:23 +0000106
107 bool isFull() const { return NumPieces == 2*WidthFactor; }
108
109 /// clear - Remove all rope pieces from this leaf.
110 void clear() {
111 while (NumPieces)
112 Pieces[--NumPieces] = RopePiece();
113 Size = 0;
114 }
115
116 unsigned getNumPieces() const { return NumPieces; }
117
118 const RopePiece &getPiece(unsigned i) const {
119 assert(i < getNumPieces() && "Invalid piece ID");
120 return Pieces[i];
121 }
122
123 const RopePieceBTreeLeaf *getNextLeafInOrder() const { return NextLeaf; }
124 void setNextLeafInOrder(const RopePieceBTreeLeaf *NL) { NextLeaf = NL; }
125
126 void FullRecomputeSizeLocally() {
127 Size = 0;
128 for (unsigned i = 0, e = getNumPieces(); i != e; ++i)
129 Size += getPiece(i).size();
130 }
131
132 /// split - Split the range containing the specified offset so that we are
133 /// guaranteed that there is a place to do an insertion at the specified
134 /// offset. The offset is relative, so "0" is the start of the node. This
135 /// returns true if the insertion could not be done in place, and returns
136 /// information in 'Res' about the piece that is percolated up.
137 bool split(unsigned Offset, InsertResult *Res);
138
139 /// insert - Insert the specified ropepiece into this tree node at the
140 /// specified offset. The offset is relative, so "0" is the start of the
141 /// node. This returns true if the insertion could not be done in place,
142 /// and returns information in 'Res' about the piece that is percolated up.
143 bool insert(unsigned Offset, const RopePiece &R, InsertResult *Res);
144
145
146 /// erase - Remove NumBytes from this node at the specified offset. We are
147 /// guaranteed that there is a split at Offset.
148 void erase(unsigned Offset, unsigned NumBytes);
149
150 static inline bool classof(const RopePieceBTreeLeaf *) { return true; }
151 static inline bool classof(const RopePieceBTreeNode *N) {
152 return N->isLeaf();
153 }
154 };
155} // end anonymous namespace
156
157/// split - Split the range containing the specified offset so that we are
158/// guaranteed that there is a place to do an insertion at the specified
159/// offset. The offset is relative, so "0" is the start of the node. This
160/// returns true if the insertion could not be done in place, and returns
161/// information in 'Res' about the piece that is percolated up.
162bool RopePieceBTreeLeaf::split(unsigned Offset, InsertResult *Res) {
163 // Find the insertion point. We are guaranteed that there is a split at the
164 // specified offset so find it.
165 if (Offset == 0 || Offset == size()) {
166 // Fastpath for a common case. There is already a splitpoint at the end.
167 return false;
168 }
169
170 // Find the piece that this offset lands in.
171 unsigned PieceOffs = 0;
172 unsigned i = 0;
173 while (Offset >= PieceOffs+Pieces[i].size()) {
174 PieceOffs += Pieces[i].size();
175 ++i;
176 }
177
178 // If there is already a split point at the specified offset, just return
179 // success.
180 if (PieceOffs == Offset)
181 return false;
182
183 // Otherwise, we need to split piece 'i' at Offset-PieceOffs. Convert Offset
184 // to being Piece relative.
185 unsigned IntraPieceOffset = Offset-PieceOffs;
186
187 // We do this by shrinking the RopePiece and then doing an insert of the tail.
188 RopePiece Tail(Pieces[i].StrData, Pieces[i].StartOffs+IntraPieceOffset,
189 Pieces[i].EndOffs);
190 Size -= Pieces[i].size();
191 Pieces[i].EndOffs = Pieces[i].StartOffs+IntraPieceOffset;
192 Size += Pieces[i].size();
193
194 return insert(Offset, Tail, Res);
195}
196
197
198/// insert - Insert the specified RopePiece into this tree node at the
199/// specified offset. The offset is relative, so "0" is the start of the
200/// node. This returns true if the insertion could not be done in place, and
201/// returns information in 'Res' about the piece that is percolated up.
202bool RopePieceBTreeLeaf::insert(unsigned Offset, const RopePiece &R,
203 InsertResult *Res) {
204 // If this node is not full, insert the piece.
205 if (!isFull()) {
206 // Find the insertion point. We are guaranteed that there is a split at the
207 // specified offset so find it.
208 unsigned i = 0, e = getNumPieces();
209 if (Offset == size()) {
210 // Fastpath for a common case.
211 i = e;
212 } else {
213 unsigned SlotOffs = 0;
214 for (; Offset > SlotOffs; ++i)
215 SlotOffs += getPiece(i).size();
216 assert(SlotOffs == Offset && "Split didn't occur before insertion!");
217 }
218
219 // For an insertion into a non-full leaf node, just insert the value in
220 // its sorted position. This requires moving later values over.
221 for (; i != e; --e)
222 Pieces[e] = Pieces[e-1];
223 Pieces[i] = R;
224 ++NumPieces;
225 Size += R.size();
226 return false;
227 }
228
229 // Otherwise, if this is leaf is full, split it in two halves. Since this
230 // node is full, it contains 2*WidthFactor values. We move the first
231 // 'WidthFactor' values to the LHS child (which we leave in this node) and
232 // move the last 'WidthFactor' values into the RHS child.
233
234 // Create the new node.
235 RopePieceBTreeLeaf *NewNode = new RopePieceBTreeLeaf();
236
237 // Move over the last 'WidthFactor' values from here to NewNode.
238 std::copy(&Pieces[WidthFactor], &Pieces[2*WidthFactor],
239 &NewNode->Pieces[0]);
240 // Replace old pieces with null RopePieces to drop refcounts.
241 std::fill(&Pieces[WidthFactor], &Pieces[2*WidthFactor], RopePiece());
242
243 // Decrease the number of values in the two nodes.
244 NewNode->NumPieces = NumPieces = WidthFactor;
245
246 // Recompute the two nodes' size.
247 NewNode->FullRecomputeSizeLocally();
248 FullRecomputeSizeLocally();
249
250 // Update the list of leaves.
251 NewNode->setNextLeafInOrder(this->getNextLeafInOrder());
252 this->setNextLeafInOrder(NewNode);
253
254 assert(Res && "No result location specified");
255 Res->LHS = this;
256 Res->RHS = NewNode;
257
258 if (this->size() >= Offset)
259 this->insert(Offset, R, 0 /*can't fail*/);
260 else
261 NewNode->insert(Offset - this->size(), R, 0 /*can't fail*/);
262 return true;
263}
264
265/// erase - Remove NumBytes from this node at the specified offset. We are
266/// guaranteed that there is a split at Offset.
267void RopePieceBTreeLeaf::erase(unsigned Offset, unsigned NumBytes) {
268 // Since we are guaranteed that there is a split at Offset, we start by
269 // finding the Piece that starts there.
270 unsigned PieceOffs = 0;
271 unsigned i = 0;
272 for (; Offset > PieceOffs; ++i)
273 PieceOffs += getPiece(i).size();
274 assert(PieceOffs == Offset && "Split didn't occur before erase!");
275
276 unsigned StartPiece = i;
277
278 // Figure out how many pieces completely cover 'NumBytes'. We want to remove
279 // all of them.
280 for (; Offset+NumBytes > PieceOffs+getPiece(i).size(); ++i)
281 PieceOffs += getPiece(i).size();
282
283 // If we exactly include the last one, include it in the region to delete.
284 if (Offset+NumBytes == PieceOffs+getPiece(i).size())
285 PieceOffs += getPiece(i).size(), ++i;
286
287 // If we completely cover some RopePieces, erase them now.
288 if (i != StartPiece) {
289 unsigned NumDeleted = i-StartPiece;
290 for (; i != getNumPieces(); ++i)
291 Pieces[i-NumDeleted] = Pieces[i];
292
293 // Drop references to dead rope pieces.
294 std::fill(&Pieces[getNumPieces()-NumDeleted], &Pieces[getNumPieces()],
295 RopePiece());
296 NumPieces -= NumDeleted;
297
298 unsigned CoverBytes = PieceOffs-Offset;
299 NumBytes -= CoverBytes;
300 Size -= CoverBytes;
301 }
302
303 // If we completely removed some stuff, we could be done.
304 if (NumBytes == 0) return;
305
306 // Okay, now might be erasing part of some Piece. If this is the case, then
307 // move the start point of the piece.
308 assert(getPiece(StartPiece).size() > NumBytes);
309 Pieces[StartPiece].StartOffs += NumBytes;
310
311 // The size of this node just shrunk by NumBytes.
312 Size -= NumBytes;
313}
314
315//===----------------------------------------------------------------------===//
316// RopePieceBTreeInterior Class
317//===----------------------------------------------------------------------===//
318
319namespace {
320 // Holds up to 2*WidthFactor children.
321 class RopePieceBTreeInterior : public RopePieceBTreeNode {
322 /// NumChildren - This holds the number of children currently active in the
323 /// Children array.
324 unsigned char NumChildren;
325 RopePieceBTreeNode *Children[2*WidthFactor];
326 public:
Chris Lattner70778c82008-04-14 20:07:03 +0000327 RopePieceBTreeInterior() : RopePieceBTreeNode(false), NumChildren(0) {}
Chris Lattner5fd3e262008-04-14 17:54:23 +0000328
329 RopePieceBTreeInterior(RopePieceBTreeNode *LHS, RopePieceBTreeNode *RHS)
330 : RopePieceBTreeNode(false) {
331 Children[0] = LHS;
332 Children[1] = RHS;
333 NumChildren = 2;
334 Size = LHS->size() + RHS->size();
335 }
336
337 bool isFull() const { return NumChildren == 2*WidthFactor; }
338
339 unsigned getNumChildren() const { return NumChildren; }
340 const RopePieceBTreeNode *getChild(unsigned i) const {
341 assert(i < NumChildren && "invalid child #");
342 return Children[i];
343 }
344 RopePieceBTreeNode *getChild(unsigned i) {
345 assert(i < NumChildren && "invalid child #");
346 return Children[i];
347 }
348
349 void FullRecomputeSizeLocally() {
350 Size = 0;
351 for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
352 Size += getChild(i)->size();
353 }
354
355
356 /// split - Split the range containing the specified offset so that we are
357 /// guaranteed that there is a place to do an insertion at the specified
358 /// offset. The offset is relative, so "0" is the start of the node. This
359 /// returns true if the insertion could not be done in place, and returns
360 /// information in 'Res' about the piece that is percolated up.
361 bool split(unsigned Offset, InsertResult *Res);
362
363
364 /// insert - Insert the specified ropepiece into this tree node at the
365 /// specified offset. The offset is relative, so "0" is the start of the
366 /// node. This returns true if the insertion could not be done in place,
367 /// and returns information in 'Res' about the piece that is percolated up.
368 bool insert(unsigned Offset, const RopePiece &R, InsertResult *Res);
369
370 /// HandleChildPiece - A child propagated an insertion result up to us.
371 /// Insert the new child, and/or propagate the result further up the tree.
372 bool HandleChildPiece(unsigned i, InsertResult &Res);
373
374 /// erase - Remove NumBytes from this node at the specified offset. We are
375 /// guaranteed that there is a split at Offset.
376 void erase(unsigned Offset, unsigned NumBytes);
377
378 static inline bool classof(const RopePieceBTreeInterior *) { return true; }
379 static inline bool classof(const RopePieceBTreeNode *N) {
380 return !N->isLeaf();
381 }
382 };
383} // end anonymous namespace
384
385/// split - Split the range containing the specified offset so that we are
386/// guaranteed that there is a place to do an insertion at the specified
387/// offset. The offset is relative, so "0" is the start of the node. This
388/// returns true if the insertion could not be done in place, and returns
389/// information in 'Res' about the piece that is percolated up.
390bool RopePieceBTreeInterior::split(unsigned Offset, InsertResult *Res) {
391 // Figure out which child to split.
392 if (Offset == 0 || Offset == size())
393 return false; // If we have an exact offset, we're already split.
394
395 unsigned ChildOffset = 0;
396 unsigned i = 0;
397 for (; Offset >= ChildOffset+getChild(i)->size(); ++i)
398 ChildOffset += getChild(i)->size();
399
400 // If already split there, we're done.
401 if (ChildOffset == Offset)
402 return false;
403
404 // Otherwise, recursively split the child.
405 if (getChild(i)->split(Offset-ChildOffset, Res))
406 return HandleChildPiece(i, *Res);
407 return false; // Done!
408}
409
410/// insert - Insert the specified ropepiece into this tree node at the
411/// specified offset. The offset is relative, so "0" is the start of the
412/// node. This returns true if the insertion could not be done in place, and
413/// returns information in 'Res' about the piece that is percolated up.
414bool RopePieceBTreeInterior::insert(unsigned Offset, const RopePiece &R,
415 InsertResult *Res) {
416 // Find the insertion point. We are guaranteed that there is a split at the
417 // specified offset so find it.
418 unsigned i = 0, e = getNumChildren();
419
420 unsigned ChildOffs = 0;
421 if (Offset == size()) {
422 // Fastpath for a common case. Insert at end of last child.
423 i = e-1;
424 ChildOffs = size()-getChild(i)->size();
425 } else {
426 for (; Offset > ChildOffs+getChild(i)->size(); ++i)
427 ChildOffs += getChild(i)->size();
428 }
429
430 Size += R.size();
431
432 // Insert at the end of this child.
433 if (getChild(i)->insert(Offset-ChildOffs, R, Res))
434 return HandleChildPiece(i, *Res);
435
436 return false;
437}
438
439/// HandleChildPiece - A child propagated an insertion result up to us.
440/// Insert the new child, and/or propagate the result further up the tree.
441bool RopePieceBTreeInterior::HandleChildPiece(unsigned i, InsertResult &Res) {
442 // Otherwise the child propagated a subtree up to us as a new child. See if
443 // we have space for it here.
444 if (!isFull()) {
445 // Replace child 'i' with the two children specified in Res.
446 if (i + 1 != getNumChildren())
447 memmove(&Children[i+2], &Children[i+1],
448 (getNumChildren()-i-1)*sizeof(Children[0]));
449 Children[i] = Res.LHS;
450 Children[i+1] = Res.RHS;
451 ++NumChildren;
452 return false;
453 }
454
455 // Okay, this node is full. Split it in half, moving WidthFactor children to
456 // a newly allocated interior node.
457
458 // Create the new node.
459 RopePieceBTreeInterior *NewNode = new RopePieceBTreeInterior();
460
461 // Move over the last 'WidthFactor' values from here to NewNode.
462 memcpy(&NewNode->Children[0], &Children[WidthFactor],
463 WidthFactor*sizeof(Children[0]));
464
465 // Decrease the number of values in the two nodes.
466 NewNode->NumChildren = NumChildren = WidthFactor;
467
468 // Finally, insert the two new children in the side the can (now) hold them.
469 if (i < WidthFactor)
470 this->HandleChildPiece(i, Res);
471 else
472 NewNode->HandleChildPiece(i-WidthFactor, Res);
473
474 // Recompute the two nodes' size.
475 NewNode->FullRecomputeSizeLocally();
476 FullRecomputeSizeLocally();
477
478 Res.LHS = this;
479 Res.RHS = NewNode;
480 return true;
481}
482
483/// erase - Remove NumBytes from this node at the specified offset. We are
484/// guaranteed that there is a split at Offset.
485void RopePieceBTreeInterior::erase(unsigned Offset, unsigned NumBytes) {
486 // This will shrink this node by NumBytes.
487 Size -= NumBytes;
488
489 // Find the first child that overlaps with Offset.
490 unsigned i = 0;
491 for (; Offset >= getChild(i)->size(); ++i)
492 Offset -= getChild(i)->size();
493
494 // Propagate the delete request into overlapping children, or completely
495 // delete the children as appropriate.
496 while (NumBytes) {
497 RopePieceBTreeNode *CurChild = getChild(i);
498
499 // If we are deleting something contained entirely in the child, pass on the
500 // request.
501 if (Offset+NumBytes < CurChild->size()) {
502 CurChild->erase(Offset, NumBytes);
503 return;
504 }
505
506 // If this deletion request starts somewhere in the middle of the child, it
507 // must be deleting to the end of the child.
508 if (Offset) {
509 unsigned BytesFromChild = CurChild->size()-Offset;
510 CurChild->erase(Offset, BytesFromChild);
511 NumBytes -= BytesFromChild;
512 ++i;
513 continue;
514 }
515
516 // If the deletion request completely covers the child, delete it and move
517 // the rest down.
518 NumBytes -= CurChild->size();
519 CurChild->Destroy();
520 --NumChildren;
521 if (i+1 != getNumChildren())
522 memmove(&Children[i], &Children[i+1],
523 (getNumChildren()-i)*sizeof(Children[0]));
524 }
525}
526
527//===----------------------------------------------------------------------===//
528// RopePieceBTreeNode Implementation
529//===----------------------------------------------------------------------===//
530
531void RopePieceBTreeNode::Destroy() {
532 if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(this))
533 delete Leaf;
534 else
535 delete cast<RopePieceBTreeInterior>(this);
536}
537
538/// split - Split the range containing the specified offset so that we are
539/// guaranteed that there is a place to do an insertion at the specified
540/// offset. The offset is relative, so "0" is the start of the node. This
541/// returns true if the insertion could not be done in place, and returns
542/// information in 'Res' about the piece that is percolated up.
543bool RopePieceBTreeNode::split(unsigned Offset, InsertResult *Res) {
544 assert(Offset <= size() && "Invalid offset to split!");
545 if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(this))
546 return Leaf->split(Offset, Res);
547 return cast<RopePieceBTreeInterior>(this)->split(Offset, Res);
548}
549
550/// insert - Insert the specified ropepiece into this tree node at the
551/// specified offset. The offset is relative, so "0" is the start of the
552/// node.
553bool RopePieceBTreeNode::insert(unsigned Offset, const RopePiece &R,
554 InsertResult *Res) {
555 assert(Offset <= size() && "Invalid offset to insert!");
556 if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(this))
557 return Leaf->insert(Offset, R, Res);
558 return cast<RopePieceBTreeInterior>(this)->insert(Offset, R, Res);
559}
560
561/// erase - Remove NumBytes from this node at the specified offset. We are
562/// guaranteed that there is a split at Offset.
563void RopePieceBTreeNode::erase(unsigned Offset, unsigned NumBytes) {
564 assert(Offset+NumBytes <= size() && "Invalid offset to erase!");
565 if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(this))
566 return Leaf->erase(Offset, NumBytes);
567 return cast<RopePieceBTreeInterior>(this)->erase(Offset, NumBytes);
568}
569
570
571//===----------------------------------------------------------------------===//
572// RopePieceBTreeIterator Implementation
573//===----------------------------------------------------------------------===//
574
575static const RopePieceBTreeLeaf *getCN(const void *P) {
576 return static_cast<const RopePieceBTreeLeaf*>(P);
577}
578
579// begin iterator.
580RopePieceBTreeIterator::RopePieceBTreeIterator(const void *n) {
581 const RopePieceBTreeNode *N = static_cast<const RopePieceBTreeNode*>(n);
582
583 // Walk down the left side of the tree until we get to a leaf.
584 while (const RopePieceBTreeInterior *IN = dyn_cast<RopePieceBTreeInterior>(N))
585 N = IN->getChild(0);
586
587 // We must have at least one leaf.
588 CurNode = cast<RopePieceBTreeLeaf>(N);
589
590 // If we found a leaf that happens to be empty, skip over it until we get
591 // to something full.
592 while (CurNode && getCN(CurNode)->getNumPieces() == 0)
593 CurNode = getCN(CurNode)->getNextLeafInOrder();
594
595 if (CurNode != 0)
596 CurPiece = &getCN(CurNode)->getPiece(0);
597 else // Empty tree, this is an end() iterator.
598 CurPiece = 0;
599 CurChar = 0;
600}
601
602void RopePieceBTreeIterator::MoveToNextPiece() {
603 if (CurPiece != &getCN(CurNode)->getPiece(getCN(CurNode)->getNumPieces()-1)) {
604 CurChar = 0;
605 ++CurPiece;
606 return;
607 }
608
609 // Find the next non-empty leaf node.
610 do
611 CurNode = getCN(CurNode)->getNextLeafInOrder();
612 while (CurNode && getCN(CurNode)->getNumPieces() == 0);
613
614 if (CurNode != 0)
615 CurPiece = &getCN(CurNode)->getPiece(0);
616 else // Hit end().
617 CurPiece = 0;
618 CurChar = 0;
619}
620
621//===----------------------------------------------------------------------===//
622// RopePieceBTree Implementation
623//===----------------------------------------------------------------------===//
624
625static RopePieceBTreeNode *getRoot(void *P) {
626 return static_cast<RopePieceBTreeNode*>(P);
627}
628
629RopePieceBTree::RopePieceBTree() {
630 Root = new RopePieceBTreeLeaf();
631}
632RopePieceBTree::RopePieceBTree(const RopePieceBTree &RHS) {
633 assert(RHS.empty() && "Can't copy non-empty tree yet");
634 Root = new RopePieceBTreeLeaf();
635}
636RopePieceBTree::~RopePieceBTree() {
637 getRoot(Root)->Destroy();
638}
639
640unsigned RopePieceBTree::size() const {
641 return getRoot(Root)->size();
642}
643
644void RopePieceBTree::clear() {
645 if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(getRoot(Root)))
646 Leaf->clear();
647 else {
648 getRoot(Root)->Destroy();
649 Root = new RopePieceBTreeLeaf();
650 }
651}
652
653void RopePieceBTree::insert(unsigned Offset, const RopePiece &R) {
654 InsertResult Result;
655 // #1. Split at Offset.
656 if (getRoot(Root)->split(Offset, &Result))
657 Root = new RopePieceBTreeInterior(Result.LHS, Result.RHS);
658
659 // #2. Do the insertion.
660 if (getRoot(Root)->insert(Offset, R, &Result))
661 Root = new RopePieceBTreeInterior(Result.LHS, Result.RHS);
662}
663
664void RopePieceBTree::erase(unsigned Offset, unsigned NumBytes) {
665 InsertResult Result;
666 // #1. Split at Offset.
667 if (getRoot(Root)->split(Offset, &Result))
668 Root = new RopePieceBTreeInterior(Result.LHS, Result.RHS);
669
670 // #2. Do the erasing.
671 getRoot(Root)->erase(Offset, NumBytes);
672}