DeltaTree.cpp revision 1.1 1 1.1 joerg //===- DeltaTree.cpp - B-Tree for Rewrite Delta tracking ------------------===//
2 1.1 joerg //
3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information.
5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 1.1 joerg //
7 1.1 joerg //===----------------------------------------------------------------------===//
8 1.1 joerg //
9 1.1 joerg // This file implements the DeltaTree and related classes.
10 1.1 joerg //
11 1.1 joerg //===----------------------------------------------------------------------===//
12 1.1 joerg
13 1.1 joerg #include "clang/Rewrite/Core/DeltaTree.h"
14 1.1 joerg #include "clang/Basic/LLVM.h"
15 1.1 joerg #include "llvm/Support/Casting.h"
16 1.1 joerg #include <cassert>
17 1.1 joerg #include <cstring>
18 1.1 joerg
19 1.1 joerg using namespace clang;
20 1.1 joerg
21 1.1 joerg /// The DeltaTree class is a multiway search tree (BTree) structure with some
22 1.1 joerg /// fancy features. B-Trees are generally more memory and cache efficient
23 1.1 joerg /// than binary trees, because they store multiple keys/values in each node.
24 1.1 joerg ///
25 1.1 joerg /// DeltaTree implements a key/value mapping from FileIndex to Delta, allowing
26 1.1 joerg /// fast lookup by FileIndex. However, an added (important) bonus is that it
27 1.1 joerg /// can also efficiently tell us the full accumulated delta for a specific
28 1.1 joerg /// file offset as well, without traversing the whole tree.
29 1.1 joerg ///
30 1.1 joerg /// The nodes of the tree are made up of instances of two classes:
31 1.1 joerg /// DeltaTreeNode and DeltaTreeInteriorNode. The later subclasses the
32 1.1 joerg /// former and adds children pointers. Each node knows the full delta of all
33 1.1 joerg /// entries (recursively) contained inside of it, which allows us to get the
34 1.1 joerg /// full delta implied by a whole subtree in constant time.
35 1.1 joerg
36 1.1 joerg namespace {
37 1.1 joerg
38 1.1 joerg /// SourceDelta - As code in the original input buffer is added and deleted,
39 1.1 joerg /// SourceDelta records are used to keep track of how the input SourceLocation
40 1.1 joerg /// object is mapped into the output buffer.
41 1.1 joerg struct SourceDelta {
42 1.1 joerg unsigned FileLoc;
43 1.1 joerg int Delta;
44 1.1 joerg
45 1.1 joerg static SourceDelta get(unsigned Loc, int D) {
46 1.1 joerg SourceDelta Delta;
47 1.1 joerg Delta.FileLoc = Loc;
48 1.1 joerg Delta.Delta = D;
49 1.1 joerg return Delta;
50 1.1 joerg }
51 1.1 joerg };
52 1.1 joerg
53 1.1 joerg /// DeltaTreeNode - The common part of all nodes.
54 1.1 joerg ///
55 1.1 joerg class DeltaTreeNode {
56 1.1 joerg public:
57 1.1 joerg struct InsertResult {
58 1.1 joerg DeltaTreeNode *LHS, *RHS;
59 1.1 joerg SourceDelta Split;
60 1.1 joerg };
61 1.1 joerg
62 1.1 joerg private:
63 1.1 joerg friend class DeltaTreeInteriorNode;
64 1.1 joerg
65 1.1 joerg /// WidthFactor - This controls the number of K/V slots held in the BTree:
66 1.1 joerg /// how wide it is. Each level of the BTree is guaranteed to have at least
67 1.1 joerg /// WidthFactor-1 K/V pairs (except the root) and may have at most
68 1.1 joerg /// 2*WidthFactor-1 K/V pairs.
69 1.1 joerg enum { WidthFactor = 8 };
70 1.1 joerg
71 1.1 joerg /// Values - This tracks the SourceDelta's currently in this node.
72 1.1 joerg SourceDelta Values[2*WidthFactor-1];
73 1.1 joerg
74 1.1 joerg /// NumValuesUsed - This tracks the number of values this node currently
75 1.1 joerg /// holds.
76 1.1 joerg unsigned char NumValuesUsed = 0;
77 1.1 joerg
78 1.1 joerg /// IsLeaf - This is true if this is a leaf of the btree. If false, this is
79 1.1 joerg /// an interior node, and is actually an instance of DeltaTreeInteriorNode.
80 1.1 joerg bool IsLeaf;
81 1.1 joerg
82 1.1 joerg /// FullDelta - This is the full delta of all the values in this node and
83 1.1 joerg /// all children nodes.
84 1.1 joerg int FullDelta = 0;
85 1.1 joerg
86 1.1 joerg public:
87 1.1 joerg DeltaTreeNode(bool isLeaf = true) : IsLeaf(isLeaf) {}
88 1.1 joerg
89 1.1 joerg bool isLeaf() const { return IsLeaf; }
90 1.1 joerg int getFullDelta() const { return FullDelta; }
91 1.1 joerg bool isFull() const { return NumValuesUsed == 2*WidthFactor-1; }
92 1.1 joerg
93 1.1 joerg unsigned getNumValuesUsed() const { return NumValuesUsed; }
94 1.1 joerg
95 1.1 joerg const SourceDelta &getValue(unsigned i) const {
96 1.1 joerg assert(i < NumValuesUsed && "Invalid value #");
97 1.1 joerg return Values[i];
98 1.1 joerg }
99 1.1 joerg
100 1.1 joerg SourceDelta &getValue(unsigned i) {
101 1.1 joerg assert(i < NumValuesUsed && "Invalid value #");
102 1.1 joerg return Values[i];
103 1.1 joerg }
104 1.1 joerg
105 1.1 joerg /// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into
106 1.1 joerg /// this node. If insertion is easy, do it and return false. Otherwise,
107 1.1 joerg /// split the node, populate InsertRes with info about the split, and return
108 1.1 joerg /// true.
109 1.1 joerg bool DoInsertion(unsigned FileIndex, int Delta, InsertResult *InsertRes);
110 1.1 joerg
111 1.1 joerg void DoSplit(InsertResult &InsertRes);
112 1.1 joerg
113 1.1 joerg
114 1.1 joerg /// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a
115 1.1 joerg /// local walk over our contained deltas.
116 1.1 joerg void RecomputeFullDeltaLocally();
117 1.1 joerg
118 1.1 joerg void Destroy();
119 1.1 joerg };
120 1.1 joerg
121 1.1 joerg /// DeltaTreeInteriorNode - When isLeaf = false, a node has child pointers.
122 1.1 joerg /// This class tracks them.
123 1.1 joerg class DeltaTreeInteriorNode : public DeltaTreeNode {
124 1.1 joerg friend class DeltaTreeNode;
125 1.1 joerg
126 1.1 joerg DeltaTreeNode *Children[2*WidthFactor];
127 1.1 joerg
128 1.1 joerg ~DeltaTreeInteriorNode() {
129 1.1 joerg for (unsigned i = 0, e = NumValuesUsed+1; i != e; ++i)
130 1.1 joerg Children[i]->Destroy();
131 1.1 joerg }
132 1.1 joerg
133 1.1 joerg public:
134 1.1 joerg DeltaTreeInteriorNode() : DeltaTreeNode(false /*nonleaf*/) {}
135 1.1 joerg
136 1.1 joerg DeltaTreeInteriorNode(const InsertResult &IR)
137 1.1 joerg : DeltaTreeNode(false /*nonleaf*/) {
138 1.1 joerg Children[0] = IR.LHS;
139 1.1 joerg Children[1] = IR.RHS;
140 1.1 joerg Values[0] = IR.Split;
141 1.1 joerg FullDelta = IR.LHS->getFullDelta()+IR.RHS->getFullDelta()+IR.Split.Delta;
142 1.1 joerg NumValuesUsed = 1;
143 1.1 joerg }
144 1.1 joerg
145 1.1 joerg const DeltaTreeNode *getChild(unsigned i) const {
146 1.1 joerg assert(i < getNumValuesUsed()+1 && "Invalid child");
147 1.1 joerg return Children[i];
148 1.1 joerg }
149 1.1 joerg
150 1.1 joerg DeltaTreeNode *getChild(unsigned i) {
151 1.1 joerg assert(i < getNumValuesUsed()+1 && "Invalid child");
152 1.1 joerg return Children[i];
153 1.1 joerg }
154 1.1 joerg
155 1.1 joerg static bool classof(const DeltaTreeNode *N) { return !N->isLeaf(); }
156 1.1 joerg };
157 1.1 joerg
158 1.1 joerg } // namespace
159 1.1 joerg
160 1.1 joerg /// Destroy - A 'virtual' destructor.
161 1.1 joerg void DeltaTreeNode::Destroy() {
162 1.1 joerg if (isLeaf())
163 1.1 joerg delete this;
164 1.1 joerg else
165 1.1 joerg delete cast<DeltaTreeInteriorNode>(this);
166 1.1 joerg }
167 1.1 joerg
168 1.1 joerg /// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a
169 1.1 joerg /// local walk over our contained deltas.
170 1.1 joerg void DeltaTreeNode::RecomputeFullDeltaLocally() {
171 1.1 joerg int NewFullDelta = 0;
172 1.1 joerg for (unsigned i = 0, e = getNumValuesUsed(); i != e; ++i)
173 1.1 joerg NewFullDelta += Values[i].Delta;
174 1.1 joerg if (auto *IN = dyn_cast<DeltaTreeInteriorNode>(this))
175 1.1 joerg for (unsigned i = 0, e = getNumValuesUsed()+1; i != e; ++i)
176 1.1 joerg NewFullDelta += IN->getChild(i)->getFullDelta();
177 1.1 joerg FullDelta = NewFullDelta;
178 1.1 joerg }
179 1.1 joerg
180 1.1 joerg /// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into
181 1.1 joerg /// this node. If insertion is easy, do it and return false. Otherwise,
182 1.1 joerg /// split the node, populate InsertRes with info about the split, and return
183 1.1 joerg /// true.
184 1.1 joerg bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta,
185 1.1 joerg InsertResult *InsertRes) {
186 1.1 joerg // Maintain full delta for this node.
187 1.1 joerg FullDelta += Delta;
188 1.1 joerg
189 1.1 joerg // Find the insertion point, the first delta whose index is >= FileIndex.
190 1.1 joerg unsigned i = 0, e = getNumValuesUsed();
191 1.1 joerg while (i != e && FileIndex > getValue(i).FileLoc)
192 1.1 joerg ++i;
193 1.1 joerg
194 1.1 joerg // If we found an a record for exactly this file index, just merge this
195 1.1 joerg // value into the pre-existing record and finish early.
196 1.1 joerg if (i != e && getValue(i).FileLoc == FileIndex) {
197 1.1 joerg // NOTE: Delta could drop to zero here. This means that the delta entry is
198 1.1 joerg // useless and could be removed. Supporting erases is more complex than
199 1.1 joerg // leaving an entry with Delta=0, so we just leave an entry with Delta=0 in
200 1.1 joerg // the tree.
201 1.1 joerg Values[i].Delta += Delta;
202 1.1 joerg return false;
203 1.1 joerg }
204 1.1 joerg
205 1.1 joerg // Otherwise, we found an insertion point, and we know that the value at the
206 1.1 joerg // specified index is > FileIndex. Handle the leaf case first.
207 1.1 joerg if (isLeaf()) {
208 1.1 joerg if (!isFull()) {
209 1.1 joerg // For an insertion into a non-full leaf node, just insert the value in
210 1.1 joerg // its sorted position. This requires moving later values over.
211 1.1 joerg if (i != e)
212 1.1 joerg memmove(&Values[i+1], &Values[i], sizeof(Values[0])*(e-i));
213 1.1 joerg Values[i] = SourceDelta::get(FileIndex, Delta);
214 1.1 joerg ++NumValuesUsed;
215 1.1 joerg return false;
216 1.1 joerg }
217 1.1 joerg
218 1.1 joerg // Otherwise, if this is leaf is full, split the node at its median, insert
219 1.1 joerg // the value into one of the children, and return the result.
220 1.1 joerg assert(InsertRes && "No result location specified");
221 1.1 joerg DoSplit(*InsertRes);
222 1.1 joerg
223 1.1 joerg if (InsertRes->Split.FileLoc > FileIndex)
224 1.1 joerg InsertRes->LHS->DoInsertion(FileIndex, Delta, nullptr /*can't fail*/);
225 1.1 joerg else
226 1.1 joerg InsertRes->RHS->DoInsertion(FileIndex, Delta, nullptr /*can't fail*/);
227 1.1 joerg return true;
228 1.1 joerg }
229 1.1 joerg
230 1.1 joerg // Otherwise, this is an interior node. Send the request down the tree.
231 1.1 joerg auto *IN = cast<DeltaTreeInteriorNode>(this);
232 1.1 joerg if (!IN->Children[i]->DoInsertion(FileIndex, Delta, InsertRes))
233 1.1 joerg return false; // If there was space in the child, just return.
234 1.1 joerg
235 1.1 joerg // Okay, this split the subtree, producing a new value and two children to
236 1.1 joerg // insert here. If this node is non-full, we can just insert it directly.
237 1.1 joerg if (!isFull()) {
238 1.1 joerg // Now that we have two nodes and a new element, insert the perclated value
239 1.1 joerg // into ourself by moving all the later values/children down, then inserting
240 1.1 joerg // the new one.
241 1.1 joerg if (i != e)
242 1.1 joerg memmove(&IN->Children[i+2], &IN->Children[i+1],
243 1.1 joerg (e-i)*sizeof(IN->Children[0]));
244 1.1 joerg IN->Children[i] = InsertRes->LHS;
245 1.1 joerg IN->Children[i+1] = InsertRes->RHS;
246 1.1 joerg
247 1.1 joerg if (e != i)
248 1.1 joerg memmove(&Values[i+1], &Values[i], (e-i)*sizeof(Values[0]));
249 1.1 joerg Values[i] = InsertRes->Split;
250 1.1 joerg ++NumValuesUsed;
251 1.1 joerg return false;
252 1.1 joerg }
253 1.1 joerg
254 1.1 joerg // Finally, if this interior node was full and a node is percolated up, split
255 1.1 joerg // ourself and return that up the chain. Start by saving all our info to
256 1.1 joerg // avoid having the split clobber it.
257 1.1 joerg IN->Children[i] = InsertRes->LHS;
258 1.1 joerg DeltaTreeNode *SubRHS = InsertRes->RHS;
259 1.1 joerg SourceDelta SubSplit = InsertRes->Split;
260 1.1 joerg
261 1.1 joerg // Do the split.
262 1.1 joerg DoSplit(*InsertRes);
263 1.1 joerg
264 1.1 joerg // Figure out where to insert SubRHS/NewSplit.
265 1.1 joerg DeltaTreeInteriorNode *InsertSide;
266 1.1 joerg if (SubSplit.FileLoc < InsertRes->Split.FileLoc)
267 1.1 joerg InsertSide = cast<DeltaTreeInteriorNode>(InsertRes->LHS);
268 1.1 joerg else
269 1.1 joerg InsertSide = cast<DeltaTreeInteriorNode>(InsertRes->RHS);
270 1.1 joerg
271 1.1 joerg // We now have a non-empty interior node 'InsertSide' to insert
272 1.1 joerg // SubRHS/SubSplit into. Find out where to insert SubSplit.
273 1.1 joerg
274 1.1 joerg // Find the insertion point, the first delta whose index is >SubSplit.FileLoc.
275 1.1 joerg i = 0; e = InsertSide->getNumValuesUsed();
276 1.1 joerg while (i != e && SubSplit.FileLoc > InsertSide->getValue(i).FileLoc)
277 1.1 joerg ++i;
278 1.1 joerg
279 1.1 joerg // Now we know that i is the place to insert the split value into. Insert it
280 1.1 joerg // and the child right after it.
281 1.1 joerg if (i != e)
282 1.1 joerg memmove(&InsertSide->Children[i+2], &InsertSide->Children[i+1],
283 1.1 joerg (e-i)*sizeof(IN->Children[0]));
284 1.1 joerg InsertSide->Children[i+1] = SubRHS;
285 1.1 joerg
286 1.1 joerg if (e != i)
287 1.1 joerg memmove(&InsertSide->Values[i+1], &InsertSide->Values[i],
288 1.1 joerg (e-i)*sizeof(Values[0]));
289 1.1 joerg InsertSide->Values[i] = SubSplit;
290 1.1 joerg ++InsertSide->NumValuesUsed;
291 1.1 joerg InsertSide->FullDelta += SubSplit.Delta + SubRHS->getFullDelta();
292 1.1 joerg return true;
293 1.1 joerg }
294 1.1 joerg
295 1.1 joerg /// DoSplit - Split the currently full node (which has 2*WidthFactor-1 values)
296 1.1 joerg /// into two subtrees each with "WidthFactor-1" values and a pivot value.
297 1.1 joerg /// Return the pieces in InsertRes.
298 1.1 joerg void DeltaTreeNode::DoSplit(InsertResult &InsertRes) {
299 1.1 joerg assert(isFull() && "Why split a non-full node?");
300 1.1 joerg
301 1.1 joerg // Since this node is full, it contains 2*WidthFactor-1 values. We move
302 1.1 joerg // the first 'WidthFactor-1' values to the LHS child (which we leave in this
303 1.1 joerg // node), propagate one value up, and move the last 'WidthFactor-1' values
304 1.1 joerg // into the RHS child.
305 1.1 joerg
306 1.1 joerg // Create the new child node.
307 1.1 joerg DeltaTreeNode *NewNode;
308 1.1 joerg if (auto *IN = dyn_cast<DeltaTreeInteriorNode>(this)) {
309 1.1 joerg // If this is an interior node, also move over 'WidthFactor' children
310 1.1 joerg // into the new node.
311 1.1 joerg DeltaTreeInteriorNode *New = new DeltaTreeInteriorNode();
312 1.1 joerg memcpy(&New->Children[0], &IN->Children[WidthFactor],
313 1.1 joerg WidthFactor*sizeof(IN->Children[0]));
314 1.1 joerg NewNode = New;
315 1.1 joerg } else {
316 1.1 joerg // Just create the new leaf node.
317 1.1 joerg NewNode = new DeltaTreeNode();
318 1.1 joerg }
319 1.1 joerg
320 1.1 joerg // Move over the last 'WidthFactor-1' values from here to NewNode.
321 1.1 joerg memcpy(&NewNode->Values[0], &Values[WidthFactor],
322 1.1 joerg (WidthFactor-1)*sizeof(Values[0]));
323 1.1 joerg
324 1.1 joerg // Decrease the number of values in the two nodes.
325 1.1 joerg NewNode->NumValuesUsed = NumValuesUsed = WidthFactor-1;
326 1.1 joerg
327 1.1 joerg // Recompute the two nodes' full delta.
328 1.1 joerg NewNode->RecomputeFullDeltaLocally();
329 1.1 joerg RecomputeFullDeltaLocally();
330 1.1 joerg
331 1.1 joerg InsertRes.LHS = this;
332 1.1 joerg InsertRes.RHS = NewNode;
333 1.1 joerg InsertRes.Split = Values[WidthFactor-1];
334 1.1 joerg }
335 1.1 joerg
336 1.1 joerg //===----------------------------------------------------------------------===//
337 1.1 joerg // DeltaTree Implementation
338 1.1 joerg //===----------------------------------------------------------------------===//
339 1.1 joerg
340 1.1 joerg //#define VERIFY_TREE
341 1.1 joerg
342 1.1 joerg #ifdef VERIFY_TREE
343 1.1 joerg /// VerifyTree - Walk the btree performing assertions on various properties to
344 1.1 joerg /// verify consistency. This is useful for debugging new changes to the tree.
345 1.1 joerg static void VerifyTree(const DeltaTreeNode *N) {
346 1.1 joerg const auto *IN = dyn_cast<DeltaTreeInteriorNode>(N);
347 1.1 joerg if (IN == 0) {
348 1.1 joerg // Verify leaves, just ensure that FullDelta matches up and the elements
349 1.1 joerg // are in proper order.
350 1.1 joerg int FullDelta = 0;
351 1.1 joerg for (unsigned i = 0, e = N->getNumValuesUsed(); i != e; ++i) {
352 1.1 joerg if (i)
353 1.1 joerg assert(N->getValue(i-1).FileLoc < N->getValue(i).FileLoc);
354 1.1 joerg FullDelta += N->getValue(i).Delta;
355 1.1 joerg }
356 1.1 joerg assert(FullDelta == N->getFullDelta());
357 1.1 joerg return;
358 1.1 joerg }
359 1.1 joerg
360 1.1 joerg // Verify interior nodes: Ensure that FullDelta matches up and the
361 1.1 joerg // elements are in proper order and the children are in proper order.
362 1.1 joerg int FullDelta = 0;
363 1.1 joerg for (unsigned i = 0, e = IN->getNumValuesUsed(); i != e; ++i) {
364 1.1 joerg const SourceDelta &IVal = N->getValue(i);
365 1.1 joerg const DeltaTreeNode *IChild = IN->getChild(i);
366 1.1 joerg if (i)
367 1.1 joerg assert(IN->getValue(i-1).FileLoc < IVal.FileLoc);
368 1.1 joerg FullDelta += IVal.Delta;
369 1.1 joerg FullDelta += IChild->getFullDelta();
370 1.1 joerg
371 1.1 joerg // The largest value in child #i should be smaller than FileLoc.
372 1.1 joerg assert(IChild->getValue(IChild->getNumValuesUsed()-1).FileLoc <
373 1.1 joerg IVal.FileLoc);
374 1.1 joerg
375 1.1 joerg // The smallest value in child #i+1 should be larger than FileLoc.
376 1.1 joerg assert(IN->getChild(i+1)->getValue(0).FileLoc > IVal.FileLoc);
377 1.1 joerg VerifyTree(IChild);
378 1.1 joerg }
379 1.1 joerg
380 1.1 joerg FullDelta += IN->getChild(IN->getNumValuesUsed())->getFullDelta();
381 1.1 joerg
382 1.1 joerg assert(FullDelta == N->getFullDelta());
383 1.1 joerg }
384 1.1 joerg #endif // VERIFY_TREE
385 1.1 joerg
386 1.1 joerg static DeltaTreeNode *getRoot(void *Root) {
387 1.1 joerg return (DeltaTreeNode*)Root;
388 1.1 joerg }
389 1.1 joerg
390 1.1 joerg DeltaTree::DeltaTree() {
391 1.1 joerg Root = new DeltaTreeNode();
392 1.1 joerg }
393 1.1 joerg
394 1.1 joerg DeltaTree::DeltaTree(const DeltaTree &RHS) {
395 1.1 joerg // Currently we only support copying when the RHS is empty.
396 1.1 joerg assert(getRoot(RHS.Root)->getNumValuesUsed() == 0 &&
397 1.1 joerg "Can only copy empty tree");
398 1.1 joerg Root = new DeltaTreeNode();
399 1.1 joerg }
400 1.1 joerg
401 1.1 joerg DeltaTree::~DeltaTree() {
402 1.1 joerg getRoot(Root)->Destroy();
403 1.1 joerg }
404 1.1 joerg
405 1.1 joerg /// getDeltaAt - Return the accumulated delta at the specified file offset.
406 1.1 joerg /// This includes all insertions or delections that occurred *before* the
407 1.1 joerg /// specified file index.
408 1.1 joerg int DeltaTree::getDeltaAt(unsigned FileIndex) const {
409 1.1 joerg const DeltaTreeNode *Node = getRoot(Root);
410 1.1 joerg
411 1.1 joerg int Result = 0;
412 1.1 joerg
413 1.1 joerg // Walk down the tree.
414 1.1 joerg while (true) {
415 1.1 joerg // For all nodes, include any local deltas before the specified file
416 1.1 joerg // index by summing them up directly. Keep track of how many were
417 1.1 joerg // included.
418 1.1 joerg unsigned NumValsGreater = 0;
419 1.1 joerg for (unsigned e = Node->getNumValuesUsed(); NumValsGreater != e;
420 1.1 joerg ++NumValsGreater) {
421 1.1 joerg const SourceDelta &Val = Node->getValue(NumValsGreater);
422 1.1 joerg
423 1.1 joerg if (Val.FileLoc >= FileIndex)
424 1.1 joerg break;
425 1.1 joerg Result += Val.Delta;
426 1.1 joerg }
427 1.1 joerg
428 1.1 joerg // If we have an interior node, include information about children and
429 1.1 joerg // recurse. Otherwise, if we have a leaf, we're done.
430 1.1 joerg const auto *IN = dyn_cast<DeltaTreeInteriorNode>(Node);
431 1.1 joerg if (!IN) return Result;
432 1.1 joerg
433 1.1 joerg // Include any children to the left of the values we skipped, all of
434 1.1 joerg // their deltas should be included as well.
435 1.1 joerg for (unsigned i = 0; i != NumValsGreater; ++i)
436 1.1 joerg Result += IN->getChild(i)->getFullDelta();
437 1.1 joerg
438 1.1 joerg // If we found exactly the value we were looking for, break off the
439 1.1 joerg // search early. There is no need to search the RHS of the value for
440 1.1 joerg // partial results.
441 1.1 joerg if (NumValsGreater != Node->getNumValuesUsed() &&
442 1.1 joerg Node->getValue(NumValsGreater).FileLoc == FileIndex)
443 1.1 joerg return Result+IN->getChild(NumValsGreater)->getFullDelta();
444 1.1 joerg
445 1.1 joerg // Otherwise, traverse down the tree. The selected subtree may be
446 1.1 joerg // partially included in the range.
447 1.1 joerg Node = IN->getChild(NumValsGreater);
448 1.1 joerg }
449 1.1 joerg // NOT REACHED.
450 1.1 joerg }
451 1.1 joerg
452 1.1 joerg /// AddDelta - When a change is made that shifts around the text buffer,
453 1.1 joerg /// this method is used to record that info. It inserts a delta of 'Delta'
454 1.1 joerg /// into the current DeltaTree at offset FileIndex.
455 1.1 joerg void DeltaTree::AddDelta(unsigned FileIndex, int Delta) {
456 1.1 joerg assert(Delta && "Adding a noop?");
457 1.1 joerg DeltaTreeNode *MyRoot = getRoot(Root);
458 1.1 joerg
459 1.1 joerg DeltaTreeNode::InsertResult InsertRes;
460 1.1 joerg if (MyRoot->DoInsertion(FileIndex, Delta, &InsertRes)) {
461 1.1 joerg Root = MyRoot = new DeltaTreeInteriorNode(InsertRes);
462 1.1 joerg }
463 1.1 joerg
464 1.1 joerg #ifdef VERIFY_TREE
465 1.1 joerg VerifyTree(MyRoot);
466 1.1 joerg #endif
467 1.1 joerg }
468