10b57cec5SDimitry Andric //===- DeltaTree.cpp - B-Tree for Rewrite Delta tracking ------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the DeltaTree and related classes.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "clang/Rewrite/Core/DeltaTree.h"
140b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
150b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
160b57cec5SDimitry Andric #include <cassert>
170b57cec5SDimitry Andric #include <cstring>
180b57cec5SDimitry Andric
190b57cec5SDimitry Andric using namespace clang;
200b57cec5SDimitry Andric
210b57cec5SDimitry Andric /// The DeltaTree class is a multiway search tree (BTree) structure with some
220b57cec5SDimitry Andric /// fancy features. B-Trees are generally more memory and cache efficient
230b57cec5SDimitry Andric /// than binary trees, because they store multiple keys/values in each node.
240b57cec5SDimitry Andric ///
250b57cec5SDimitry Andric /// DeltaTree implements a key/value mapping from FileIndex to Delta, allowing
260b57cec5SDimitry Andric /// fast lookup by FileIndex. However, an added (important) bonus is that it
270b57cec5SDimitry Andric /// can also efficiently tell us the full accumulated delta for a specific
280b57cec5SDimitry Andric /// file offset as well, without traversing the whole tree.
290b57cec5SDimitry Andric ///
300b57cec5SDimitry Andric /// The nodes of the tree are made up of instances of two classes:
310b57cec5SDimitry Andric /// DeltaTreeNode and DeltaTreeInteriorNode. The later subclasses the
320b57cec5SDimitry Andric /// former and adds children pointers. Each node knows the full delta of all
330b57cec5SDimitry Andric /// entries (recursively) contained inside of it, which allows us to get the
340b57cec5SDimitry Andric /// full delta implied by a whole subtree in constant time.
350b57cec5SDimitry Andric
360b57cec5SDimitry Andric namespace {
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric /// SourceDelta - As code in the original input buffer is added and deleted,
390b57cec5SDimitry Andric /// SourceDelta records are used to keep track of how the input SourceLocation
400b57cec5SDimitry Andric /// object is mapped into the output buffer.
410b57cec5SDimitry Andric struct SourceDelta {
420b57cec5SDimitry Andric unsigned FileLoc;
430b57cec5SDimitry Andric int Delta;
440b57cec5SDimitry Andric
get__anon9d934e970111::SourceDelta450b57cec5SDimitry Andric static SourceDelta get(unsigned Loc, int D) {
460b57cec5SDimitry Andric SourceDelta Delta;
470b57cec5SDimitry Andric Delta.FileLoc = Loc;
480b57cec5SDimitry Andric Delta.Delta = D;
490b57cec5SDimitry Andric return Delta;
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric };
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric /// DeltaTreeNode - The common part of all nodes.
540b57cec5SDimitry Andric ///
550b57cec5SDimitry Andric class DeltaTreeNode {
560b57cec5SDimitry Andric public:
570b57cec5SDimitry Andric struct InsertResult {
580b57cec5SDimitry Andric DeltaTreeNode *LHS, *RHS;
590b57cec5SDimitry Andric SourceDelta Split;
600b57cec5SDimitry Andric };
610b57cec5SDimitry Andric
620b57cec5SDimitry Andric private:
630b57cec5SDimitry Andric friend class DeltaTreeInteriorNode;
640b57cec5SDimitry Andric
650b57cec5SDimitry Andric /// WidthFactor - This controls the number of K/V slots held in the BTree:
660b57cec5SDimitry Andric /// how wide it is. Each level of the BTree is guaranteed to have at least
670b57cec5SDimitry Andric /// WidthFactor-1 K/V pairs (except the root) and may have at most
680b57cec5SDimitry Andric /// 2*WidthFactor-1 K/V pairs.
690b57cec5SDimitry Andric enum { WidthFactor = 8 };
700b57cec5SDimitry Andric
710b57cec5SDimitry Andric /// Values - This tracks the SourceDelta's currently in this node.
720b57cec5SDimitry Andric SourceDelta Values[2*WidthFactor-1];
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric /// NumValuesUsed - This tracks the number of values this node currently
750b57cec5SDimitry Andric /// holds.
760b57cec5SDimitry Andric unsigned char NumValuesUsed = 0;
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric /// IsLeaf - This is true if this is a leaf of the btree. If false, this is
790b57cec5SDimitry Andric /// an interior node, and is actually an instance of DeltaTreeInteriorNode.
800b57cec5SDimitry Andric bool IsLeaf;
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric /// FullDelta - This is the full delta of all the values in this node and
830b57cec5SDimitry Andric /// all children nodes.
840b57cec5SDimitry Andric int FullDelta = 0;
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric public:
DeltaTreeNode(bool isLeaf=true)870b57cec5SDimitry Andric DeltaTreeNode(bool isLeaf = true) : IsLeaf(isLeaf) {}
880b57cec5SDimitry Andric
isLeaf() const890b57cec5SDimitry Andric bool isLeaf() const { return IsLeaf; }
getFullDelta() const900b57cec5SDimitry Andric int getFullDelta() const { return FullDelta; }
isFull() const910b57cec5SDimitry Andric bool isFull() const { return NumValuesUsed == 2*WidthFactor-1; }
920b57cec5SDimitry Andric
getNumValuesUsed() const930b57cec5SDimitry Andric unsigned getNumValuesUsed() const { return NumValuesUsed; }
940b57cec5SDimitry Andric
getValue(unsigned i) const950b57cec5SDimitry Andric const SourceDelta &getValue(unsigned i) const {
960b57cec5SDimitry Andric assert(i < NumValuesUsed && "Invalid value #");
970b57cec5SDimitry Andric return Values[i];
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric
getValue(unsigned i)1000b57cec5SDimitry Andric SourceDelta &getValue(unsigned i) {
1010b57cec5SDimitry Andric assert(i < NumValuesUsed && "Invalid value #");
1020b57cec5SDimitry Andric return Values[i];
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric
1050b57cec5SDimitry Andric /// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into
1060b57cec5SDimitry Andric /// this node. If insertion is easy, do it and return false. Otherwise,
1070b57cec5SDimitry Andric /// split the node, populate InsertRes with info about the split, and return
1080b57cec5SDimitry Andric /// true.
1090b57cec5SDimitry Andric bool DoInsertion(unsigned FileIndex, int Delta, InsertResult *InsertRes);
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric void DoSplit(InsertResult &InsertRes);
1120b57cec5SDimitry Andric
1130b57cec5SDimitry Andric
1140b57cec5SDimitry Andric /// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a
1150b57cec5SDimitry Andric /// local walk over our contained deltas.
1160b57cec5SDimitry Andric void RecomputeFullDeltaLocally();
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric void Destroy();
1190b57cec5SDimitry Andric };
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric /// DeltaTreeInteriorNode - When isLeaf = false, a node has child pointers.
1220b57cec5SDimitry Andric /// This class tracks them.
1230b57cec5SDimitry Andric class DeltaTreeInteriorNode : public DeltaTreeNode {
1240b57cec5SDimitry Andric friend class DeltaTreeNode;
1250b57cec5SDimitry Andric
1260b57cec5SDimitry Andric DeltaTreeNode *Children[2*WidthFactor];
1270b57cec5SDimitry Andric
~DeltaTreeInteriorNode()1280b57cec5SDimitry Andric ~DeltaTreeInteriorNode() {
1290b57cec5SDimitry Andric for (unsigned i = 0, e = NumValuesUsed+1; i != e; ++i)
1300b57cec5SDimitry Andric Children[i]->Destroy();
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric
1330b57cec5SDimitry Andric public:
DeltaTreeInteriorNode()1340b57cec5SDimitry Andric DeltaTreeInteriorNode() : DeltaTreeNode(false /*nonleaf*/) {}
1350b57cec5SDimitry Andric
DeltaTreeInteriorNode(const InsertResult & IR)1360b57cec5SDimitry Andric DeltaTreeInteriorNode(const InsertResult &IR)
1370b57cec5SDimitry Andric : DeltaTreeNode(false /*nonleaf*/) {
1380b57cec5SDimitry Andric Children[0] = IR.LHS;
1390b57cec5SDimitry Andric Children[1] = IR.RHS;
1400b57cec5SDimitry Andric Values[0] = IR.Split;
1410b57cec5SDimitry Andric FullDelta = IR.LHS->getFullDelta()+IR.RHS->getFullDelta()+IR.Split.Delta;
1420b57cec5SDimitry Andric NumValuesUsed = 1;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric
getChild(unsigned i) const1450b57cec5SDimitry Andric const DeltaTreeNode *getChild(unsigned i) const {
1460b57cec5SDimitry Andric assert(i < getNumValuesUsed()+1 && "Invalid child");
1470b57cec5SDimitry Andric return Children[i];
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric
getChild(unsigned i)1500b57cec5SDimitry Andric DeltaTreeNode *getChild(unsigned i) {
1510b57cec5SDimitry Andric assert(i < getNumValuesUsed()+1 && "Invalid child");
1520b57cec5SDimitry Andric return Children[i];
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric
classof(const DeltaTreeNode * N)1550b57cec5SDimitry Andric static bool classof(const DeltaTreeNode *N) { return !N->isLeaf(); }
1560b57cec5SDimitry Andric };
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric } // namespace
1590b57cec5SDimitry Andric
1600b57cec5SDimitry Andric /// Destroy - A 'virtual' destructor.
Destroy()1610b57cec5SDimitry Andric void DeltaTreeNode::Destroy() {
1620b57cec5SDimitry Andric if (isLeaf())
1630b57cec5SDimitry Andric delete this;
1640b57cec5SDimitry Andric else
1650b57cec5SDimitry Andric delete cast<DeltaTreeInteriorNode>(this);
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric /// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a
1690b57cec5SDimitry Andric /// local walk over our contained deltas.
RecomputeFullDeltaLocally()1700b57cec5SDimitry Andric void DeltaTreeNode::RecomputeFullDeltaLocally() {
1710b57cec5SDimitry Andric int NewFullDelta = 0;
1720b57cec5SDimitry Andric for (unsigned i = 0, e = getNumValuesUsed(); i != e; ++i)
1730b57cec5SDimitry Andric NewFullDelta += Values[i].Delta;
1740b57cec5SDimitry Andric if (auto *IN = dyn_cast<DeltaTreeInteriorNode>(this))
1750b57cec5SDimitry Andric for (unsigned i = 0, e = getNumValuesUsed()+1; i != e; ++i)
1760b57cec5SDimitry Andric NewFullDelta += IN->getChild(i)->getFullDelta();
1770b57cec5SDimitry Andric FullDelta = NewFullDelta;
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric
1800b57cec5SDimitry Andric /// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into
1810b57cec5SDimitry Andric /// this node. If insertion is easy, do it and return false. Otherwise,
1820b57cec5SDimitry Andric /// split the node, populate InsertRes with info about the split, and return
1830b57cec5SDimitry Andric /// true.
DoInsertion(unsigned FileIndex,int Delta,InsertResult * InsertRes)1840b57cec5SDimitry Andric bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta,
1850b57cec5SDimitry Andric InsertResult *InsertRes) {
1860b57cec5SDimitry Andric // Maintain full delta for this node.
1870b57cec5SDimitry Andric FullDelta += Delta;
1880b57cec5SDimitry Andric
1890b57cec5SDimitry Andric // Find the insertion point, the first delta whose index is >= FileIndex.
1900b57cec5SDimitry Andric unsigned i = 0, e = getNumValuesUsed();
1910b57cec5SDimitry Andric while (i != e && FileIndex > getValue(i).FileLoc)
1920b57cec5SDimitry Andric ++i;
1930b57cec5SDimitry Andric
1940b57cec5SDimitry Andric // If we found an a record for exactly this file index, just merge this
1950b57cec5SDimitry Andric // value into the pre-existing record and finish early.
1960b57cec5SDimitry Andric if (i != e && getValue(i).FileLoc == FileIndex) {
1970b57cec5SDimitry Andric // NOTE: Delta could drop to zero here. This means that the delta entry is
1980b57cec5SDimitry Andric // useless and could be removed. Supporting erases is more complex than
1990b57cec5SDimitry Andric // leaving an entry with Delta=0, so we just leave an entry with Delta=0 in
2000b57cec5SDimitry Andric // the tree.
2010b57cec5SDimitry Andric Values[i].Delta += Delta;
2020b57cec5SDimitry Andric return false;
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric
2050b57cec5SDimitry Andric // Otherwise, we found an insertion point, and we know that the value at the
2060b57cec5SDimitry Andric // specified index is > FileIndex. Handle the leaf case first.
2070b57cec5SDimitry Andric if (isLeaf()) {
2080b57cec5SDimitry Andric if (!isFull()) {
2090b57cec5SDimitry Andric // For an insertion into a non-full leaf node, just insert the value in
2100b57cec5SDimitry Andric // its sorted position. This requires moving later values over.
2110b57cec5SDimitry Andric if (i != e)
2120b57cec5SDimitry Andric memmove(&Values[i+1], &Values[i], sizeof(Values[0])*(e-i));
2130b57cec5SDimitry Andric Values[i] = SourceDelta::get(FileIndex, Delta);
2140b57cec5SDimitry Andric ++NumValuesUsed;
2150b57cec5SDimitry Andric return false;
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric
2180b57cec5SDimitry Andric // Otherwise, if this is leaf is full, split the node at its median, insert
2190b57cec5SDimitry Andric // the value into one of the children, and return the result.
2200b57cec5SDimitry Andric assert(InsertRes && "No result location specified");
2210b57cec5SDimitry Andric DoSplit(*InsertRes);
2220b57cec5SDimitry Andric
2230b57cec5SDimitry Andric if (InsertRes->Split.FileLoc > FileIndex)
2240b57cec5SDimitry Andric InsertRes->LHS->DoInsertion(FileIndex, Delta, nullptr /*can't fail*/);
2250b57cec5SDimitry Andric else
2260b57cec5SDimitry Andric InsertRes->RHS->DoInsertion(FileIndex, Delta, nullptr /*can't fail*/);
2270b57cec5SDimitry Andric return true;
2280b57cec5SDimitry Andric }
2290b57cec5SDimitry Andric
2300b57cec5SDimitry Andric // Otherwise, this is an interior node. Send the request down the tree.
2310b57cec5SDimitry Andric auto *IN = cast<DeltaTreeInteriorNode>(this);
2320b57cec5SDimitry Andric if (!IN->Children[i]->DoInsertion(FileIndex, Delta, InsertRes))
2330b57cec5SDimitry Andric return false; // If there was space in the child, just return.
2340b57cec5SDimitry Andric
2350b57cec5SDimitry Andric // Okay, this split the subtree, producing a new value and two children to
2360b57cec5SDimitry Andric // insert here. If this node is non-full, we can just insert it directly.
2370b57cec5SDimitry Andric if (!isFull()) {
2380b57cec5SDimitry Andric // Now that we have two nodes and a new element, insert the perclated value
2390b57cec5SDimitry Andric // into ourself by moving all the later values/children down, then inserting
2400b57cec5SDimitry Andric // the new one.
2410b57cec5SDimitry Andric if (i != e)
2420b57cec5SDimitry Andric memmove(&IN->Children[i+2], &IN->Children[i+1],
2430b57cec5SDimitry Andric (e-i)*sizeof(IN->Children[0]));
2440b57cec5SDimitry Andric IN->Children[i] = InsertRes->LHS;
2450b57cec5SDimitry Andric IN->Children[i+1] = InsertRes->RHS;
2460b57cec5SDimitry Andric
2470b57cec5SDimitry Andric if (e != i)
2480b57cec5SDimitry Andric memmove(&Values[i+1], &Values[i], (e-i)*sizeof(Values[0]));
2490b57cec5SDimitry Andric Values[i] = InsertRes->Split;
2500b57cec5SDimitry Andric ++NumValuesUsed;
2510b57cec5SDimitry Andric return false;
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric
2540b57cec5SDimitry Andric // Finally, if this interior node was full and a node is percolated up, split
2550b57cec5SDimitry Andric // ourself and return that up the chain. Start by saving all our info to
2560b57cec5SDimitry Andric // avoid having the split clobber it.
2570b57cec5SDimitry Andric IN->Children[i] = InsertRes->LHS;
2580b57cec5SDimitry Andric DeltaTreeNode *SubRHS = InsertRes->RHS;
2590b57cec5SDimitry Andric SourceDelta SubSplit = InsertRes->Split;
2600b57cec5SDimitry Andric
2610b57cec5SDimitry Andric // Do the split.
2620b57cec5SDimitry Andric DoSplit(*InsertRes);
2630b57cec5SDimitry Andric
2640b57cec5SDimitry Andric // Figure out where to insert SubRHS/NewSplit.
2650b57cec5SDimitry Andric DeltaTreeInteriorNode *InsertSide;
2660b57cec5SDimitry Andric if (SubSplit.FileLoc < InsertRes->Split.FileLoc)
2670b57cec5SDimitry Andric InsertSide = cast<DeltaTreeInteriorNode>(InsertRes->LHS);
2680b57cec5SDimitry Andric else
2690b57cec5SDimitry Andric InsertSide = cast<DeltaTreeInteriorNode>(InsertRes->RHS);
2700b57cec5SDimitry Andric
2710b57cec5SDimitry Andric // We now have a non-empty interior node 'InsertSide' to insert
2720b57cec5SDimitry Andric // SubRHS/SubSplit into. Find out where to insert SubSplit.
2730b57cec5SDimitry Andric
2740b57cec5SDimitry Andric // Find the insertion point, the first delta whose index is >SubSplit.FileLoc.
2750b57cec5SDimitry Andric i = 0; e = InsertSide->getNumValuesUsed();
2760b57cec5SDimitry Andric while (i != e && SubSplit.FileLoc > InsertSide->getValue(i).FileLoc)
2770b57cec5SDimitry Andric ++i;
2780b57cec5SDimitry Andric
2790b57cec5SDimitry Andric // Now we know that i is the place to insert the split value into. Insert it
2800b57cec5SDimitry Andric // and the child right after it.
2810b57cec5SDimitry Andric if (i != e)
2820b57cec5SDimitry Andric memmove(&InsertSide->Children[i+2], &InsertSide->Children[i+1],
2830b57cec5SDimitry Andric (e-i)*sizeof(IN->Children[0]));
2840b57cec5SDimitry Andric InsertSide->Children[i+1] = SubRHS;
2850b57cec5SDimitry Andric
2860b57cec5SDimitry Andric if (e != i)
2870b57cec5SDimitry Andric memmove(&InsertSide->Values[i+1], &InsertSide->Values[i],
2880b57cec5SDimitry Andric (e-i)*sizeof(Values[0]));
2890b57cec5SDimitry Andric InsertSide->Values[i] = SubSplit;
2900b57cec5SDimitry Andric ++InsertSide->NumValuesUsed;
2910b57cec5SDimitry Andric InsertSide->FullDelta += SubSplit.Delta + SubRHS->getFullDelta();
2920b57cec5SDimitry Andric return true;
2930b57cec5SDimitry Andric }
2940b57cec5SDimitry Andric
2950b57cec5SDimitry Andric /// DoSplit - Split the currently full node (which has 2*WidthFactor-1 values)
2960b57cec5SDimitry Andric /// into two subtrees each with "WidthFactor-1" values and a pivot value.
2970b57cec5SDimitry Andric /// Return the pieces in InsertRes.
DoSplit(InsertResult & InsertRes)2980b57cec5SDimitry Andric void DeltaTreeNode::DoSplit(InsertResult &InsertRes) {
2990b57cec5SDimitry Andric assert(isFull() && "Why split a non-full node?");
3000b57cec5SDimitry Andric
3010b57cec5SDimitry Andric // Since this node is full, it contains 2*WidthFactor-1 values. We move
3020b57cec5SDimitry Andric // the first 'WidthFactor-1' values to the LHS child (which we leave in this
3030b57cec5SDimitry Andric // node), propagate one value up, and move the last 'WidthFactor-1' values
3040b57cec5SDimitry Andric // into the RHS child.
3050b57cec5SDimitry Andric
3060b57cec5SDimitry Andric // Create the new child node.
3070b57cec5SDimitry Andric DeltaTreeNode *NewNode;
3080b57cec5SDimitry Andric if (auto *IN = dyn_cast<DeltaTreeInteriorNode>(this)) {
3090b57cec5SDimitry Andric // If this is an interior node, also move over 'WidthFactor' children
3100b57cec5SDimitry Andric // into the new node.
3110b57cec5SDimitry Andric DeltaTreeInteriorNode *New = new DeltaTreeInteriorNode();
3120b57cec5SDimitry Andric memcpy(&New->Children[0], &IN->Children[WidthFactor],
3130b57cec5SDimitry Andric WidthFactor*sizeof(IN->Children[0]));
3140b57cec5SDimitry Andric NewNode = New;
3150b57cec5SDimitry Andric } else {
3160b57cec5SDimitry Andric // Just create the new leaf node.
3170b57cec5SDimitry Andric NewNode = new DeltaTreeNode();
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric
3200b57cec5SDimitry Andric // Move over the last 'WidthFactor-1' values from here to NewNode.
3210b57cec5SDimitry Andric memcpy(&NewNode->Values[0], &Values[WidthFactor],
3220b57cec5SDimitry Andric (WidthFactor-1)*sizeof(Values[0]));
3230b57cec5SDimitry Andric
3240b57cec5SDimitry Andric // Decrease the number of values in the two nodes.
3250b57cec5SDimitry Andric NewNode->NumValuesUsed = NumValuesUsed = WidthFactor-1;
3260b57cec5SDimitry Andric
3270b57cec5SDimitry Andric // Recompute the two nodes' full delta.
3280b57cec5SDimitry Andric NewNode->RecomputeFullDeltaLocally();
3290b57cec5SDimitry Andric RecomputeFullDeltaLocally();
3300b57cec5SDimitry Andric
3310b57cec5SDimitry Andric InsertRes.LHS = this;
3320b57cec5SDimitry Andric InsertRes.RHS = NewNode;
3330b57cec5SDimitry Andric InsertRes.Split = Values[WidthFactor-1];
3340b57cec5SDimitry Andric }
3350b57cec5SDimitry Andric
3360b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3370b57cec5SDimitry Andric // DeltaTree Implementation
3380b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3390b57cec5SDimitry Andric
3400b57cec5SDimitry Andric //#define VERIFY_TREE
3410b57cec5SDimitry Andric
3420b57cec5SDimitry Andric #ifdef VERIFY_TREE
3430b57cec5SDimitry Andric /// VerifyTree - Walk the btree performing assertions on various properties to
3440b57cec5SDimitry Andric /// verify consistency. This is useful for debugging new changes to the tree.
VerifyTree(const DeltaTreeNode * N)3450b57cec5SDimitry Andric static void VerifyTree(const DeltaTreeNode *N) {
3460b57cec5SDimitry Andric const auto *IN = dyn_cast<DeltaTreeInteriorNode>(N);
3470b57cec5SDimitry Andric if (IN == 0) {
3480b57cec5SDimitry Andric // Verify leaves, just ensure that FullDelta matches up and the elements
3490b57cec5SDimitry Andric // are in proper order.
3500b57cec5SDimitry Andric int FullDelta = 0;
3510b57cec5SDimitry Andric for (unsigned i = 0, e = N->getNumValuesUsed(); i != e; ++i) {
3520b57cec5SDimitry Andric if (i)
3530b57cec5SDimitry Andric assert(N->getValue(i-1).FileLoc < N->getValue(i).FileLoc);
3540b57cec5SDimitry Andric FullDelta += N->getValue(i).Delta;
3550b57cec5SDimitry Andric }
3560b57cec5SDimitry Andric assert(FullDelta == N->getFullDelta());
3570b57cec5SDimitry Andric return;
3580b57cec5SDimitry Andric }
3590b57cec5SDimitry Andric
3600b57cec5SDimitry Andric // Verify interior nodes: Ensure that FullDelta matches up and the
3610b57cec5SDimitry Andric // elements are in proper order and the children are in proper order.
3620b57cec5SDimitry Andric int FullDelta = 0;
3630b57cec5SDimitry Andric for (unsigned i = 0, e = IN->getNumValuesUsed(); i != e; ++i) {
3640b57cec5SDimitry Andric const SourceDelta &IVal = N->getValue(i);
3650b57cec5SDimitry Andric const DeltaTreeNode *IChild = IN->getChild(i);
3660b57cec5SDimitry Andric if (i)
3670b57cec5SDimitry Andric assert(IN->getValue(i-1).FileLoc < IVal.FileLoc);
3680b57cec5SDimitry Andric FullDelta += IVal.Delta;
3690b57cec5SDimitry Andric FullDelta += IChild->getFullDelta();
3700b57cec5SDimitry Andric
3710b57cec5SDimitry Andric // The largest value in child #i should be smaller than FileLoc.
3720b57cec5SDimitry Andric assert(IChild->getValue(IChild->getNumValuesUsed()-1).FileLoc <
3730b57cec5SDimitry Andric IVal.FileLoc);
3740b57cec5SDimitry Andric
3750b57cec5SDimitry Andric // The smallest value in child #i+1 should be larger than FileLoc.
3760b57cec5SDimitry Andric assert(IN->getChild(i+1)->getValue(0).FileLoc > IVal.FileLoc);
3770b57cec5SDimitry Andric VerifyTree(IChild);
3780b57cec5SDimitry Andric }
3790b57cec5SDimitry Andric
3800b57cec5SDimitry Andric FullDelta += IN->getChild(IN->getNumValuesUsed())->getFullDelta();
3810b57cec5SDimitry Andric
3820b57cec5SDimitry Andric assert(FullDelta == N->getFullDelta());
3830b57cec5SDimitry Andric }
3840b57cec5SDimitry Andric #endif // VERIFY_TREE
3850b57cec5SDimitry Andric
getRoot(void * Root)3860b57cec5SDimitry Andric static DeltaTreeNode *getRoot(void *Root) {
3870b57cec5SDimitry Andric return (DeltaTreeNode*)Root;
3880b57cec5SDimitry Andric }
3890b57cec5SDimitry Andric
DeltaTree()3900b57cec5SDimitry Andric DeltaTree::DeltaTree() {
3910b57cec5SDimitry Andric Root = new DeltaTreeNode();
3920b57cec5SDimitry Andric }
3930b57cec5SDimitry Andric
DeltaTree(const DeltaTree & RHS)3940b57cec5SDimitry Andric DeltaTree::DeltaTree(const DeltaTree &RHS) {
3950b57cec5SDimitry Andric // Currently we only support copying when the RHS is empty.
3960b57cec5SDimitry Andric assert(getRoot(RHS.Root)->getNumValuesUsed() == 0 &&
3970b57cec5SDimitry Andric "Can only copy empty tree");
3980b57cec5SDimitry Andric Root = new DeltaTreeNode();
3990b57cec5SDimitry Andric }
4000b57cec5SDimitry Andric
~DeltaTree()4010b57cec5SDimitry Andric DeltaTree::~DeltaTree() {
4020b57cec5SDimitry Andric getRoot(Root)->Destroy();
4030b57cec5SDimitry Andric }
4040b57cec5SDimitry Andric
4050b57cec5SDimitry Andric /// getDeltaAt - Return the accumulated delta at the specified file offset.
4060b57cec5SDimitry Andric /// This includes all insertions or delections that occurred *before* the
4070b57cec5SDimitry Andric /// specified file index.
getDeltaAt(unsigned FileIndex) const4080b57cec5SDimitry Andric int DeltaTree::getDeltaAt(unsigned FileIndex) const {
4090b57cec5SDimitry Andric const DeltaTreeNode *Node = getRoot(Root);
4100b57cec5SDimitry Andric
4110b57cec5SDimitry Andric int Result = 0;
4120b57cec5SDimitry Andric
4130b57cec5SDimitry Andric // Walk down the tree.
4140b57cec5SDimitry Andric while (true) {
4150b57cec5SDimitry Andric // For all nodes, include any local deltas before the specified file
4160b57cec5SDimitry Andric // index by summing them up directly. Keep track of how many were
4170b57cec5SDimitry Andric // included.
4180b57cec5SDimitry Andric unsigned NumValsGreater = 0;
4190b57cec5SDimitry Andric for (unsigned e = Node->getNumValuesUsed(); NumValsGreater != e;
4200b57cec5SDimitry Andric ++NumValsGreater) {
4210b57cec5SDimitry Andric const SourceDelta &Val = Node->getValue(NumValsGreater);
4220b57cec5SDimitry Andric
4230b57cec5SDimitry Andric if (Val.FileLoc >= FileIndex)
4240b57cec5SDimitry Andric break;
4250b57cec5SDimitry Andric Result += Val.Delta;
4260b57cec5SDimitry Andric }
4270b57cec5SDimitry Andric
4280b57cec5SDimitry Andric // If we have an interior node, include information about children and
4290b57cec5SDimitry Andric // recurse. Otherwise, if we have a leaf, we're done.
4300b57cec5SDimitry Andric const auto *IN = dyn_cast<DeltaTreeInteriorNode>(Node);
4310b57cec5SDimitry Andric if (!IN) return Result;
4320b57cec5SDimitry Andric
4330b57cec5SDimitry Andric // Include any children to the left of the values we skipped, all of
4340b57cec5SDimitry Andric // their deltas should be included as well.
4350b57cec5SDimitry Andric for (unsigned i = 0; i != NumValsGreater; ++i)
4360b57cec5SDimitry Andric Result += IN->getChild(i)->getFullDelta();
4370b57cec5SDimitry Andric
4380b57cec5SDimitry Andric // If we found exactly the value we were looking for, break off the
4390b57cec5SDimitry Andric // search early. There is no need to search the RHS of the value for
4400b57cec5SDimitry Andric // partial results.
4410b57cec5SDimitry Andric if (NumValsGreater != Node->getNumValuesUsed() &&
4420b57cec5SDimitry Andric Node->getValue(NumValsGreater).FileLoc == FileIndex)
4430b57cec5SDimitry Andric return Result+IN->getChild(NumValsGreater)->getFullDelta();
4440b57cec5SDimitry Andric
4450b57cec5SDimitry Andric // Otherwise, traverse down the tree. The selected subtree may be
4460b57cec5SDimitry Andric // partially included in the range.
4470b57cec5SDimitry Andric Node = IN->getChild(NumValsGreater);
4480b57cec5SDimitry Andric }
4490b57cec5SDimitry Andric // NOT REACHED.
4500b57cec5SDimitry Andric }
4510b57cec5SDimitry Andric
4520b57cec5SDimitry Andric /// AddDelta - When a change is made that shifts around the text buffer,
4530b57cec5SDimitry Andric /// this method is used to record that info. It inserts a delta of 'Delta'
4540b57cec5SDimitry Andric /// into the current DeltaTree at offset FileIndex.
AddDelta(unsigned FileIndex,int Delta)4550b57cec5SDimitry Andric void DeltaTree::AddDelta(unsigned FileIndex, int Delta) {
4560b57cec5SDimitry Andric assert(Delta && "Adding a noop?");
4570b57cec5SDimitry Andric DeltaTreeNode *MyRoot = getRoot(Root);
4580b57cec5SDimitry Andric
4590b57cec5SDimitry Andric DeltaTreeNode::InsertResult InsertRes;
4600b57cec5SDimitry Andric if (MyRoot->DoInsertion(FileIndex, Delta, &InsertRes)) {
461*fe6060f1SDimitry Andric Root = new DeltaTreeInteriorNode(InsertRes);
462*fe6060f1SDimitry Andric #ifdef VERIFY_TREE
463*fe6060f1SDimitry Andric MyRoot = Root;
464*fe6060f1SDimitry Andric #endif
4650b57cec5SDimitry Andric }
4660b57cec5SDimitry Andric
4670b57cec5SDimitry Andric #ifdef VERIFY_TREE
4680b57cec5SDimitry Andric VerifyTree(MyRoot);
4690b57cec5SDimitry Andric #endif
4700b57cec5SDimitry Andric }
471