17330f729Sjoerg //===- DeltaTree.cpp - B-Tree for Rewrite Delta tracking ------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file implements the DeltaTree and related classes.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg
137330f729Sjoerg #include "clang/Rewrite/Core/DeltaTree.h"
147330f729Sjoerg #include "clang/Basic/LLVM.h"
157330f729Sjoerg #include "llvm/Support/Casting.h"
167330f729Sjoerg #include <cassert>
177330f729Sjoerg #include <cstring>
187330f729Sjoerg
197330f729Sjoerg using namespace clang;
207330f729Sjoerg
217330f729Sjoerg /// The DeltaTree class is a multiway search tree (BTree) structure with some
227330f729Sjoerg /// fancy features. B-Trees are generally more memory and cache efficient
237330f729Sjoerg /// than binary trees, because they store multiple keys/values in each node.
247330f729Sjoerg ///
257330f729Sjoerg /// DeltaTree implements a key/value mapping from FileIndex to Delta, allowing
267330f729Sjoerg /// fast lookup by FileIndex. However, an added (important) bonus is that it
277330f729Sjoerg /// can also efficiently tell us the full accumulated delta for a specific
287330f729Sjoerg /// file offset as well, without traversing the whole tree.
297330f729Sjoerg ///
307330f729Sjoerg /// The nodes of the tree are made up of instances of two classes:
317330f729Sjoerg /// DeltaTreeNode and DeltaTreeInteriorNode. The later subclasses the
327330f729Sjoerg /// former and adds children pointers. Each node knows the full delta of all
337330f729Sjoerg /// entries (recursively) contained inside of it, which allows us to get the
347330f729Sjoerg /// full delta implied by a whole subtree in constant time.
357330f729Sjoerg
367330f729Sjoerg namespace {
377330f729Sjoerg
387330f729Sjoerg /// SourceDelta - As code in the original input buffer is added and deleted,
397330f729Sjoerg /// SourceDelta records are used to keep track of how the input SourceLocation
407330f729Sjoerg /// object is mapped into the output buffer.
417330f729Sjoerg struct SourceDelta {
427330f729Sjoerg unsigned FileLoc;
437330f729Sjoerg int Delta;
447330f729Sjoerg
get__anonb6a907500111::SourceDelta457330f729Sjoerg static SourceDelta get(unsigned Loc, int D) {
467330f729Sjoerg SourceDelta Delta;
477330f729Sjoerg Delta.FileLoc = Loc;
487330f729Sjoerg Delta.Delta = D;
497330f729Sjoerg return Delta;
507330f729Sjoerg }
517330f729Sjoerg };
527330f729Sjoerg
537330f729Sjoerg /// DeltaTreeNode - The common part of all nodes.
547330f729Sjoerg ///
557330f729Sjoerg class DeltaTreeNode {
567330f729Sjoerg public:
577330f729Sjoerg struct InsertResult {
587330f729Sjoerg DeltaTreeNode *LHS, *RHS;
597330f729Sjoerg SourceDelta Split;
607330f729Sjoerg };
617330f729Sjoerg
627330f729Sjoerg private:
637330f729Sjoerg friend class DeltaTreeInteriorNode;
647330f729Sjoerg
657330f729Sjoerg /// WidthFactor - This controls the number of K/V slots held in the BTree:
667330f729Sjoerg /// how wide it is. Each level of the BTree is guaranteed to have at least
677330f729Sjoerg /// WidthFactor-1 K/V pairs (except the root) and may have at most
687330f729Sjoerg /// 2*WidthFactor-1 K/V pairs.
697330f729Sjoerg enum { WidthFactor = 8 };
707330f729Sjoerg
717330f729Sjoerg /// Values - This tracks the SourceDelta's currently in this node.
727330f729Sjoerg SourceDelta Values[2*WidthFactor-1];
737330f729Sjoerg
747330f729Sjoerg /// NumValuesUsed - This tracks the number of values this node currently
757330f729Sjoerg /// holds.
767330f729Sjoerg unsigned char NumValuesUsed = 0;
777330f729Sjoerg
787330f729Sjoerg /// IsLeaf - This is true if this is a leaf of the btree. If false, this is
797330f729Sjoerg /// an interior node, and is actually an instance of DeltaTreeInteriorNode.
807330f729Sjoerg bool IsLeaf;
817330f729Sjoerg
827330f729Sjoerg /// FullDelta - This is the full delta of all the values in this node and
837330f729Sjoerg /// all children nodes.
847330f729Sjoerg int FullDelta = 0;
857330f729Sjoerg
867330f729Sjoerg public:
DeltaTreeNode(bool isLeaf=true)877330f729Sjoerg DeltaTreeNode(bool isLeaf = true) : IsLeaf(isLeaf) {}
887330f729Sjoerg
isLeaf() const897330f729Sjoerg bool isLeaf() const { return IsLeaf; }
getFullDelta() const907330f729Sjoerg int getFullDelta() const { return FullDelta; }
isFull() const917330f729Sjoerg bool isFull() const { return NumValuesUsed == 2*WidthFactor-1; }
927330f729Sjoerg
getNumValuesUsed() const937330f729Sjoerg unsigned getNumValuesUsed() const { return NumValuesUsed; }
947330f729Sjoerg
getValue(unsigned i) const957330f729Sjoerg const SourceDelta &getValue(unsigned i) const {
967330f729Sjoerg assert(i < NumValuesUsed && "Invalid value #");
977330f729Sjoerg return Values[i];
987330f729Sjoerg }
997330f729Sjoerg
getValue(unsigned i)1007330f729Sjoerg SourceDelta &getValue(unsigned i) {
1017330f729Sjoerg assert(i < NumValuesUsed && "Invalid value #");
1027330f729Sjoerg return Values[i];
1037330f729Sjoerg }
1047330f729Sjoerg
1057330f729Sjoerg /// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into
1067330f729Sjoerg /// this node. If insertion is easy, do it and return false. Otherwise,
1077330f729Sjoerg /// split the node, populate InsertRes with info about the split, and return
1087330f729Sjoerg /// true.
1097330f729Sjoerg bool DoInsertion(unsigned FileIndex, int Delta, InsertResult *InsertRes);
1107330f729Sjoerg
1117330f729Sjoerg void DoSplit(InsertResult &InsertRes);
1127330f729Sjoerg
1137330f729Sjoerg
1147330f729Sjoerg /// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a
1157330f729Sjoerg /// local walk over our contained deltas.
1167330f729Sjoerg void RecomputeFullDeltaLocally();
1177330f729Sjoerg
1187330f729Sjoerg void Destroy();
1197330f729Sjoerg };
1207330f729Sjoerg
1217330f729Sjoerg /// DeltaTreeInteriorNode - When isLeaf = false, a node has child pointers.
1227330f729Sjoerg /// This class tracks them.
1237330f729Sjoerg class DeltaTreeInteriorNode : public DeltaTreeNode {
1247330f729Sjoerg friend class DeltaTreeNode;
1257330f729Sjoerg
1267330f729Sjoerg DeltaTreeNode *Children[2*WidthFactor];
1277330f729Sjoerg
~DeltaTreeInteriorNode()1287330f729Sjoerg ~DeltaTreeInteriorNode() {
1297330f729Sjoerg for (unsigned i = 0, e = NumValuesUsed+1; i != e; ++i)
1307330f729Sjoerg Children[i]->Destroy();
1317330f729Sjoerg }
1327330f729Sjoerg
1337330f729Sjoerg public:
DeltaTreeInteriorNode()1347330f729Sjoerg DeltaTreeInteriorNode() : DeltaTreeNode(false /*nonleaf*/) {}
1357330f729Sjoerg
DeltaTreeInteriorNode(const InsertResult & IR)1367330f729Sjoerg DeltaTreeInteriorNode(const InsertResult &IR)
1377330f729Sjoerg : DeltaTreeNode(false /*nonleaf*/) {
1387330f729Sjoerg Children[0] = IR.LHS;
1397330f729Sjoerg Children[1] = IR.RHS;
1407330f729Sjoerg Values[0] = IR.Split;
1417330f729Sjoerg FullDelta = IR.LHS->getFullDelta()+IR.RHS->getFullDelta()+IR.Split.Delta;
1427330f729Sjoerg NumValuesUsed = 1;
1437330f729Sjoerg }
1447330f729Sjoerg
getChild(unsigned i) const1457330f729Sjoerg const DeltaTreeNode *getChild(unsigned i) const {
1467330f729Sjoerg assert(i < getNumValuesUsed()+1 && "Invalid child");
1477330f729Sjoerg return Children[i];
1487330f729Sjoerg }
1497330f729Sjoerg
getChild(unsigned i)1507330f729Sjoerg DeltaTreeNode *getChild(unsigned i) {
1517330f729Sjoerg assert(i < getNumValuesUsed()+1 && "Invalid child");
1527330f729Sjoerg return Children[i];
1537330f729Sjoerg }
1547330f729Sjoerg
classof(const DeltaTreeNode * N)1557330f729Sjoerg static bool classof(const DeltaTreeNode *N) { return !N->isLeaf(); }
1567330f729Sjoerg };
1577330f729Sjoerg
1587330f729Sjoerg } // namespace
1597330f729Sjoerg
1607330f729Sjoerg /// Destroy - A 'virtual' destructor.
Destroy()1617330f729Sjoerg void DeltaTreeNode::Destroy() {
1627330f729Sjoerg if (isLeaf())
1637330f729Sjoerg delete this;
1647330f729Sjoerg else
1657330f729Sjoerg delete cast<DeltaTreeInteriorNode>(this);
1667330f729Sjoerg }
1677330f729Sjoerg
1687330f729Sjoerg /// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a
1697330f729Sjoerg /// local walk over our contained deltas.
RecomputeFullDeltaLocally()1707330f729Sjoerg void DeltaTreeNode::RecomputeFullDeltaLocally() {
1717330f729Sjoerg int NewFullDelta = 0;
1727330f729Sjoerg for (unsigned i = 0, e = getNumValuesUsed(); i != e; ++i)
1737330f729Sjoerg NewFullDelta += Values[i].Delta;
1747330f729Sjoerg if (auto *IN = dyn_cast<DeltaTreeInteriorNode>(this))
1757330f729Sjoerg for (unsigned i = 0, e = getNumValuesUsed()+1; i != e; ++i)
1767330f729Sjoerg NewFullDelta += IN->getChild(i)->getFullDelta();
1777330f729Sjoerg FullDelta = NewFullDelta;
1787330f729Sjoerg }
1797330f729Sjoerg
1807330f729Sjoerg /// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into
1817330f729Sjoerg /// this node. If insertion is easy, do it and return false. Otherwise,
1827330f729Sjoerg /// split the node, populate InsertRes with info about the split, and return
1837330f729Sjoerg /// true.
DoInsertion(unsigned FileIndex,int Delta,InsertResult * InsertRes)1847330f729Sjoerg bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta,
1857330f729Sjoerg InsertResult *InsertRes) {
1867330f729Sjoerg // Maintain full delta for this node.
1877330f729Sjoerg FullDelta += Delta;
1887330f729Sjoerg
1897330f729Sjoerg // Find the insertion point, the first delta whose index is >= FileIndex.
1907330f729Sjoerg unsigned i = 0, e = getNumValuesUsed();
1917330f729Sjoerg while (i != e && FileIndex > getValue(i).FileLoc)
1927330f729Sjoerg ++i;
1937330f729Sjoerg
1947330f729Sjoerg // If we found an a record for exactly this file index, just merge this
1957330f729Sjoerg // value into the pre-existing record and finish early.
1967330f729Sjoerg if (i != e && getValue(i).FileLoc == FileIndex) {
1977330f729Sjoerg // NOTE: Delta could drop to zero here. This means that the delta entry is
1987330f729Sjoerg // useless and could be removed. Supporting erases is more complex than
1997330f729Sjoerg // leaving an entry with Delta=0, so we just leave an entry with Delta=0 in
2007330f729Sjoerg // the tree.
2017330f729Sjoerg Values[i].Delta += Delta;
2027330f729Sjoerg return false;
2037330f729Sjoerg }
2047330f729Sjoerg
2057330f729Sjoerg // Otherwise, we found an insertion point, and we know that the value at the
2067330f729Sjoerg // specified index is > FileIndex. Handle the leaf case first.
2077330f729Sjoerg if (isLeaf()) {
2087330f729Sjoerg if (!isFull()) {
2097330f729Sjoerg // For an insertion into a non-full leaf node, just insert the value in
2107330f729Sjoerg // its sorted position. This requires moving later values over.
2117330f729Sjoerg if (i != e)
2127330f729Sjoerg memmove(&Values[i+1], &Values[i], sizeof(Values[0])*(e-i));
2137330f729Sjoerg Values[i] = SourceDelta::get(FileIndex, Delta);
2147330f729Sjoerg ++NumValuesUsed;
2157330f729Sjoerg return false;
2167330f729Sjoerg }
2177330f729Sjoerg
2187330f729Sjoerg // Otherwise, if this is leaf is full, split the node at its median, insert
2197330f729Sjoerg // the value into one of the children, and return the result.
2207330f729Sjoerg assert(InsertRes && "No result location specified");
2217330f729Sjoerg DoSplit(*InsertRes);
2227330f729Sjoerg
2237330f729Sjoerg if (InsertRes->Split.FileLoc > FileIndex)
2247330f729Sjoerg InsertRes->LHS->DoInsertion(FileIndex, Delta, nullptr /*can't fail*/);
2257330f729Sjoerg else
2267330f729Sjoerg InsertRes->RHS->DoInsertion(FileIndex, Delta, nullptr /*can't fail*/);
2277330f729Sjoerg return true;
2287330f729Sjoerg }
2297330f729Sjoerg
2307330f729Sjoerg // Otherwise, this is an interior node. Send the request down the tree.
2317330f729Sjoerg auto *IN = cast<DeltaTreeInteriorNode>(this);
2327330f729Sjoerg if (!IN->Children[i]->DoInsertion(FileIndex, Delta, InsertRes))
2337330f729Sjoerg return false; // If there was space in the child, just return.
2347330f729Sjoerg
2357330f729Sjoerg // Okay, this split the subtree, producing a new value and two children to
2367330f729Sjoerg // insert here. If this node is non-full, we can just insert it directly.
2377330f729Sjoerg if (!isFull()) {
2387330f729Sjoerg // Now that we have two nodes and a new element, insert the perclated value
2397330f729Sjoerg // into ourself by moving all the later values/children down, then inserting
2407330f729Sjoerg // the new one.
2417330f729Sjoerg if (i != e)
2427330f729Sjoerg memmove(&IN->Children[i+2], &IN->Children[i+1],
2437330f729Sjoerg (e-i)*sizeof(IN->Children[0]));
2447330f729Sjoerg IN->Children[i] = InsertRes->LHS;
2457330f729Sjoerg IN->Children[i+1] = InsertRes->RHS;
2467330f729Sjoerg
2477330f729Sjoerg if (e != i)
2487330f729Sjoerg memmove(&Values[i+1], &Values[i], (e-i)*sizeof(Values[0]));
2497330f729Sjoerg Values[i] = InsertRes->Split;
2507330f729Sjoerg ++NumValuesUsed;
2517330f729Sjoerg return false;
2527330f729Sjoerg }
2537330f729Sjoerg
2547330f729Sjoerg // Finally, if this interior node was full and a node is percolated up, split
2557330f729Sjoerg // ourself and return that up the chain. Start by saving all our info to
2567330f729Sjoerg // avoid having the split clobber it.
2577330f729Sjoerg IN->Children[i] = InsertRes->LHS;
2587330f729Sjoerg DeltaTreeNode *SubRHS = InsertRes->RHS;
2597330f729Sjoerg SourceDelta SubSplit = InsertRes->Split;
2607330f729Sjoerg
2617330f729Sjoerg // Do the split.
2627330f729Sjoerg DoSplit(*InsertRes);
2637330f729Sjoerg
2647330f729Sjoerg // Figure out where to insert SubRHS/NewSplit.
2657330f729Sjoerg DeltaTreeInteriorNode *InsertSide;
2667330f729Sjoerg if (SubSplit.FileLoc < InsertRes->Split.FileLoc)
2677330f729Sjoerg InsertSide = cast<DeltaTreeInteriorNode>(InsertRes->LHS);
2687330f729Sjoerg else
2697330f729Sjoerg InsertSide = cast<DeltaTreeInteriorNode>(InsertRes->RHS);
2707330f729Sjoerg
2717330f729Sjoerg // We now have a non-empty interior node 'InsertSide' to insert
2727330f729Sjoerg // SubRHS/SubSplit into. Find out where to insert SubSplit.
2737330f729Sjoerg
2747330f729Sjoerg // Find the insertion point, the first delta whose index is >SubSplit.FileLoc.
2757330f729Sjoerg i = 0; e = InsertSide->getNumValuesUsed();
2767330f729Sjoerg while (i != e && SubSplit.FileLoc > InsertSide->getValue(i).FileLoc)
2777330f729Sjoerg ++i;
2787330f729Sjoerg
2797330f729Sjoerg // Now we know that i is the place to insert the split value into. Insert it
2807330f729Sjoerg // and the child right after it.
2817330f729Sjoerg if (i != e)
2827330f729Sjoerg memmove(&InsertSide->Children[i+2], &InsertSide->Children[i+1],
2837330f729Sjoerg (e-i)*sizeof(IN->Children[0]));
2847330f729Sjoerg InsertSide->Children[i+1] = SubRHS;
2857330f729Sjoerg
2867330f729Sjoerg if (e != i)
2877330f729Sjoerg memmove(&InsertSide->Values[i+1], &InsertSide->Values[i],
2887330f729Sjoerg (e-i)*sizeof(Values[0]));
2897330f729Sjoerg InsertSide->Values[i] = SubSplit;
2907330f729Sjoerg ++InsertSide->NumValuesUsed;
2917330f729Sjoerg InsertSide->FullDelta += SubSplit.Delta + SubRHS->getFullDelta();
2927330f729Sjoerg return true;
2937330f729Sjoerg }
2947330f729Sjoerg
2957330f729Sjoerg /// DoSplit - Split the currently full node (which has 2*WidthFactor-1 values)
2967330f729Sjoerg /// into two subtrees each with "WidthFactor-1" values and a pivot value.
2977330f729Sjoerg /// Return the pieces in InsertRes.
DoSplit(InsertResult & InsertRes)2987330f729Sjoerg void DeltaTreeNode::DoSplit(InsertResult &InsertRes) {
2997330f729Sjoerg assert(isFull() && "Why split a non-full node?");
3007330f729Sjoerg
3017330f729Sjoerg // Since this node is full, it contains 2*WidthFactor-1 values. We move
3027330f729Sjoerg // the first 'WidthFactor-1' values to the LHS child (which we leave in this
3037330f729Sjoerg // node), propagate one value up, and move the last 'WidthFactor-1' values
3047330f729Sjoerg // into the RHS child.
3057330f729Sjoerg
3067330f729Sjoerg // Create the new child node.
3077330f729Sjoerg DeltaTreeNode *NewNode;
3087330f729Sjoerg if (auto *IN = dyn_cast<DeltaTreeInteriorNode>(this)) {
3097330f729Sjoerg // If this is an interior node, also move over 'WidthFactor' children
3107330f729Sjoerg // into the new node.
3117330f729Sjoerg DeltaTreeInteriorNode *New = new DeltaTreeInteriorNode();
3127330f729Sjoerg memcpy(&New->Children[0], &IN->Children[WidthFactor],
3137330f729Sjoerg WidthFactor*sizeof(IN->Children[0]));
3147330f729Sjoerg NewNode = New;
3157330f729Sjoerg } else {
3167330f729Sjoerg // Just create the new leaf node.
3177330f729Sjoerg NewNode = new DeltaTreeNode();
3187330f729Sjoerg }
3197330f729Sjoerg
3207330f729Sjoerg // Move over the last 'WidthFactor-1' values from here to NewNode.
3217330f729Sjoerg memcpy(&NewNode->Values[0], &Values[WidthFactor],
3227330f729Sjoerg (WidthFactor-1)*sizeof(Values[0]));
3237330f729Sjoerg
3247330f729Sjoerg // Decrease the number of values in the two nodes.
3257330f729Sjoerg NewNode->NumValuesUsed = NumValuesUsed = WidthFactor-1;
3267330f729Sjoerg
3277330f729Sjoerg // Recompute the two nodes' full delta.
3287330f729Sjoerg NewNode->RecomputeFullDeltaLocally();
3297330f729Sjoerg RecomputeFullDeltaLocally();
3307330f729Sjoerg
3317330f729Sjoerg InsertRes.LHS = this;
3327330f729Sjoerg InsertRes.RHS = NewNode;
3337330f729Sjoerg InsertRes.Split = Values[WidthFactor-1];
3347330f729Sjoerg }
3357330f729Sjoerg
3367330f729Sjoerg //===----------------------------------------------------------------------===//
3377330f729Sjoerg // DeltaTree Implementation
3387330f729Sjoerg //===----------------------------------------------------------------------===//
3397330f729Sjoerg
3407330f729Sjoerg //#define VERIFY_TREE
3417330f729Sjoerg
3427330f729Sjoerg #ifdef VERIFY_TREE
3437330f729Sjoerg /// VerifyTree - Walk the btree performing assertions on various properties to
3447330f729Sjoerg /// verify consistency. This is useful for debugging new changes to the tree.
VerifyTree(const DeltaTreeNode * N)3457330f729Sjoerg static void VerifyTree(const DeltaTreeNode *N) {
3467330f729Sjoerg const auto *IN = dyn_cast<DeltaTreeInteriorNode>(N);
3477330f729Sjoerg if (IN == 0) {
3487330f729Sjoerg // Verify leaves, just ensure that FullDelta matches up and the elements
3497330f729Sjoerg // are in proper order.
3507330f729Sjoerg int FullDelta = 0;
3517330f729Sjoerg for (unsigned i = 0, e = N->getNumValuesUsed(); i != e; ++i) {
3527330f729Sjoerg if (i)
3537330f729Sjoerg assert(N->getValue(i-1).FileLoc < N->getValue(i).FileLoc);
3547330f729Sjoerg FullDelta += N->getValue(i).Delta;
3557330f729Sjoerg }
3567330f729Sjoerg assert(FullDelta == N->getFullDelta());
3577330f729Sjoerg return;
3587330f729Sjoerg }
3597330f729Sjoerg
3607330f729Sjoerg // Verify interior nodes: Ensure that FullDelta matches up and the
3617330f729Sjoerg // elements are in proper order and the children are in proper order.
3627330f729Sjoerg int FullDelta = 0;
3637330f729Sjoerg for (unsigned i = 0, e = IN->getNumValuesUsed(); i != e; ++i) {
3647330f729Sjoerg const SourceDelta &IVal = N->getValue(i);
3657330f729Sjoerg const DeltaTreeNode *IChild = IN->getChild(i);
3667330f729Sjoerg if (i)
3677330f729Sjoerg assert(IN->getValue(i-1).FileLoc < IVal.FileLoc);
3687330f729Sjoerg FullDelta += IVal.Delta;
3697330f729Sjoerg FullDelta += IChild->getFullDelta();
3707330f729Sjoerg
3717330f729Sjoerg // The largest value in child #i should be smaller than FileLoc.
3727330f729Sjoerg assert(IChild->getValue(IChild->getNumValuesUsed()-1).FileLoc <
3737330f729Sjoerg IVal.FileLoc);
3747330f729Sjoerg
3757330f729Sjoerg // The smallest value in child #i+1 should be larger than FileLoc.
3767330f729Sjoerg assert(IN->getChild(i+1)->getValue(0).FileLoc > IVal.FileLoc);
3777330f729Sjoerg VerifyTree(IChild);
3787330f729Sjoerg }
3797330f729Sjoerg
3807330f729Sjoerg FullDelta += IN->getChild(IN->getNumValuesUsed())->getFullDelta();
3817330f729Sjoerg
3827330f729Sjoerg assert(FullDelta == N->getFullDelta());
3837330f729Sjoerg }
3847330f729Sjoerg #endif // VERIFY_TREE
3857330f729Sjoerg
getRoot(void * Root)3867330f729Sjoerg static DeltaTreeNode *getRoot(void *Root) {
3877330f729Sjoerg return (DeltaTreeNode*)Root;
3887330f729Sjoerg }
3897330f729Sjoerg
DeltaTree()3907330f729Sjoerg DeltaTree::DeltaTree() {
3917330f729Sjoerg Root = new DeltaTreeNode();
3927330f729Sjoerg }
3937330f729Sjoerg
DeltaTree(const DeltaTree & RHS)3947330f729Sjoerg DeltaTree::DeltaTree(const DeltaTree &RHS) {
3957330f729Sjoerg // Currently we only support copying when the RHS is empty.
3967330f729Sjoerg assert(getRoot(RHS.Root)->getNumValuesUsed() == 0 &&
3977330f729Sjoerg "Can only copy empty tree");
3987330f729Sjoerg Root = new DeltaTreeNode();
3997330f729Sjoerg }
4007330f729Sjoerg
~DeltaTree()4017330f729Sjoerg DeltaTree::~DeltaTree() {
4027330f729Sjoerg getRoot(Root)->Destroy();
4037330f729Sjoerg }
4047330f729Sjoerg
4057330f729Sjoerg /// getDeltaAt - Return the accumulated delta at the specified file offset.
4067330f729Sjoerg /// This includes all insertions or delections that occurred *before* the
4077330f729Sjoerg /// specified file index.
getDeltaAt(unsigned FileIndex) const4087330f729Sjoerg int DeltaTree::getDeltaAt(unsigned FileIndex) const {
4097330f729Sjoerg const DeltaTreeNode *Node = getRoot(Root);
4107330f729Sjoerg
4117330f729Sjoerg int Result = 0;
4127330f729Sjoerg
4137330f729Sjoerg // Walk down the tree.
4147330f729Sjoerg while (true) {
4157330f729Sjoerg // For all nodes, include any local deltas before the specified file
4167330f729Sjoerg // index by summing them up directly. Keep track of how many were
4177330f729Sjoerg // included.
4187330f729Sjoerg unsigned NumValsGreater = 0;
4197330f729Sjoerg for (unsigned e = Node->getNumValuesUsed(); NumValsGreater != e;
4207330f729Sjoerg ++NumValsGreater) {
4217330f729Sjoerg const SourceDelta &Val = Node->getValue(NumValsGreater);
4227330f729Sjoerg
4237330f729Sjoerg if (Val.FileLoc >= FileIndex)
4247330f729Sjoerg break;
4257330f729Sjoerg Result += Val.Delta;
4267330f729Sjoerg }
4277330f729Sjoerg
4287330f729Sjoerg // If we have an interior node, include information about children and
4297330f729Sjoerg // recurse. Otherwise, if we have a leaf, we're done.
4307330f729Sjoerg const auto *IN = dyn_cast<DeltaTreeInteriorNode>(Node);
4317330f729Sjoerg if (!IN) return Result;
4327330f729Sjoerg
4337330f729Sjoerg // Include any children to the left of the values we skipped, all of
4347330f729Sjoerg // their deltas should be included as well.
4357330f729Sjoerg for (unsigned i = 0; i != NumValsGreater; ++i)
4367330f729Sjoerg Result += IN->getChild(i)->getFullDelta();
4377330f729Sjoerg
4387330f729Sjoerg // If we found exactly the value we were looking for, break off the
4397330f729Sjoerg // search early. There is no need to search the RHS of the value for
4407330f729Sjoerg // partial results.
4417330f729Sjoerg if (NumValsGreater != Node->getNumValuesUsed() &&
4427330f729Sjoerg Node->getValue(NumValsGreater).FileLoc == FileIndex)
4437330f729Sjoerg return Result+IN->getChild(NumValsGreater)->getFullDelta();
4447330f729Sjoerg
4457330f729Sjoerg // Otherwise, traverse down the tree. The selected subtree may be
4467330f729Sjoerg // partially included in the range.
4477330f729Sjoerg Node = IN->getChild(NumValsGreater);
4487330f729Sjoerg }
4497330f729Sjoerg // NOT REACHED.
4507330f729Sjoerg }
4517330f729Sjoerg
4527330f729Sjoerg /// AddDelta - When a change is made that shifts around the text buffer,
4537330f729Sjoerg /// this method is used to record that info. It inserts a delta of 'Delta'
4547330f729Sjoerg /// into the current DeltaTree at offset FileIndex.
AddDelta(unsigned FileIndex,int Delta)4557330f729Sjoerg void DeltaTree::AddDelta(unsigned FileIndex, int Delta) {
4567330f729Sjoerg assert(Delta && "Adding a noop?");
4577330f729Sjoerg DeltaTreeNode *MyRoot = getRoot(Root);
4587330f729Sjoerg
4597330f729Sjoerg DeltaTreeNode::InsertResult InsertRes;
4607330f729Sjoerg if (MyRoot->DoInsertion(FileIndex, Delta, &InsertRes)) {
461*e038c9c4Sjoerg Root = new DeltaTreeInteriorNode(InsertRes);
462*e038c9c4Sjoerg #ifdef VERIFY_TREE
463*e038c9c4Sjoerg MyRoot = Root;
464*e038c9c4Sjoerg #endif
4657330f729Sjoerg }
4667330f729Sjoerg
4677330f729Sjoerg #ifdef VERIFY_TREE
4687330f729Sjoerg VerifyTree(MyRoot);
4697330f729Sjoerg #endif
4707330f729Sjoerg }
471