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.1.2 joerg Root = new DeltaTreeInteriorNode(InsertRes); 462 1.1.1.2 joerg #ifdef VERIFY_TREE 463 1.1.1.2 joerg MyRoot = Root; 464 1.1.1.2 joerg #endif 465 1.1 joerg } 466 1.1 joerg 467 1.1 joerg #ifdef VERIFY_TREE 468 1.1 joerg VerifyTree(MyRoot); 469 1.1 joerg #endif 470 1.1 joerg } 471