From ac19a35444ce8726eda6034091215152e54e3ed3 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Fri, 26 Nov 2010 01:39:40 +0000 Subject: [PATCH] Move tree navigation to a new Path class that doesn't have to be a template. The path also holds a reference to the root node, and that allows important iterator accessors like start() and stop() to have no conditional code. (When the compiler is clever enough to remove it.) llvm-svn: 120165 --- include/llvm/ADT/IntervalMap.h | 557 ++++++++++++++++----------------- lib/Support/IntervalMap.cpp | 103 +++++- 2 files changed, 364 insertions(+), 296 deletions(-) diff --git a/include/llvm/ADT/IntervalMap.h b/include/llvm/ADT/IntervalMap.h index 314af509239..b571b952096 100644 --- a/include/llvm/ADT/IntervalMap.h +++ b/include/llvm/ADT/IntervalMap.h @@ -403,7 +403,7 @@ public: /// subtree - Access the i'th subtree reference in a branch node. /// This depends on branch nodes storing the NodeRef array as their first /// member. - NodeRef &subtree(unsigned i) { + NodeRef &subtree(unsigned i) const { return reinterpret_cast(pip.getPointer())[i]; } @@ -699,6 +699,161 @@ public: }; +//===----------------------------------------------------------------------===// +//--- Path ---// +//===----------------------------------------------------------------------===// +// +// A Path is used by iterators to represent a position in a B+-tree, and the +// path to get there from the root. +// +// The Path class also constains the tree navigation code that doesn't have to +// be templatized. +// +//===----------------------------------------------------------------------===// + +class Path { + /// Entry - Each step in the path is a node pointer and an offset into that + /// node. + struct Entry { + void *node; + unsigned size; + unsigned offset; + + Entry(void *Node, unsigned Size, unsigned Offset) + : node(Node), size(Size), offset(Offset) {} + + Entry(NodeRef Node, unsigned Offset) + : node(&Node.subtree(0)), size(Node.size()), offset(Offset) {} + + NodeRef &subtree(unsigned i) const { + return reinterpret_cast(node)[i]; + } + }; + + /// path - The path entries, path[0] is the root node, path.back() is a leaf. + SmallVector path; + +public: + // Node accessors. + template NodeT &node(unsigned Level) const { + return *reinterpret_cast(path[Level].node); + } + unsigned size(unsigned Level) const { return path[Level].size; } + unsigned offset(unsigned Level) const { return path[Level].offset; } + unsigned &offset(unsigned Level) { return path[Level].offset; } + + // Leaf accessors. + template NodeT &leaf() const { + return *reinterpret_cast(path.back().node); + } + unsigned leafSize() const { return path.back().size; } + unsigned leafOffset() const { return path.back().offset; } + unsigned &leafOffset() { return path.back().offset; } + + /// valid - Return true if path is at a valid node, not at end(). + bool valid() const { + return !path.empty() && path.front().offset < path.front().size; + } + + /// height - Return the height of the tree corresponding to this path. + /// This matches map->height in a full path. + unsigned height() const { return path.size() - 1; } + + /// subtree - Get the subtree referenced from Level. When the path is + /// consistent, node(Level + 1) == subtree(Level). + /// @param Level 0..height-1. The leaves have no subtrees. + NodeRef &subtree(unsigned Level) const { + return path[Level].subtree(path[Level].offset); + } + + /// push - Add entry to path. + /// @param Node Node to add, should be subtree(path.size()-1). + /// @param Offset Offset into Node. + void push(NodeRef Node, unsigned Offset) { + path.push_back(Entry(Node, Offset)); + } + + /// setSize - Set the size of a node both in the path and in the tree. + /// @param Level 0..height. Note that setting the root size won't change + /// map->rootSize. + /// @param Size New node size. + void setSize(unsigned Level, unsigned Size) { + path[Level].size = Size; + if (Level) + subtree(Level - 1).setSize(Size); + } + + /// setRoot - Clear the path and set a new root node. + /// @param Node New root node. + /// @param Size New root size. + /// @param Offset Offset into root node. + void setRoot(void *Node, unsigned Size, unsigned Offset) { + path.clear(); + path.push_back(Entry(Node, Size, Offset)); + } + + /// replaceRoot - Replace the current root node with two new entries after the + /// tree height has increased. + /// @param Root The new root node. + /// @param Size Number of entries in the new root. + /// @param Offsets Offsets into the root and first branch nodes. + void replaceRoot(void *Root, unsigned Size, IdxPair Offsets); + + /// getLeftSibling - Get the left sibling node at Level, or a null NodeRef. + /// @param Level Get the sibling to node(Level). + /// @return Left sibling, or NodeRef(). + NodeRef getLeftSibling(unsigned Level) const; + + /// moveLeft - Move path to the left sibling at Level. Leave nodes below Level + /// unaltered. + /// @param Level Move node(Level). + void moveLeft(unsigned Level); + + /// fillLeft - Grow path to Height by taking leftmost branches. + /// @param Height The target height. + void fillLeft(unsigned Height) { + while (height() < Height) + push(subtree(height()), 0); + } + + /// getLeftSibling - Get the left sibling node at Level, or a null NodeRef. + /// @param Level Get the sinbling to node(Level). + /// @return Left sibling, or NodeRef(). + NodeRef getRightSibling(unsigned Level) const; + + /// moveRight - Move path to the left sibling at Level. Leave nodes below + /// Level unaltered. + /// @param Level Move node(Level). + void moveRight(unsigned Level); + + /// atLastBranch - Return true if the path is at the last branch of the node + /// at Level. + /// @param Level Node to examine. + bool atLastBranch(unsigned Level) const { + return path[Level].offset == path[Level].size - 1; + } + + /// legalizeForInsert - Prepare the path for an insertion at Level. When the + /// path is at end(), node(Level) may not be a legal node. legalizeForInsert + /// ensures that node(Level) is real by moving back to the last node at Level, + /// and setting offset(Level) to size(Level) if required. + /// @param Level The level where an insertion is about to take place. + void legalizeForInsert(unsigned Level) { + if (valid()) + return; + moveLeft(Level); + ++path[Level].offset; + } + +#ifndef NDEBUG + void dump() const { + for (unsigned l = 0, e = path.size(); l != e; ++l) + errs() << l << ": " << path[l].node << ' ' << path[l].size << ' ' + << path[l].offset << '\n'; + } +#endif +}; + } // namespace IntervalMapImpl @@ -1103,107 +1258,54 @@ class IntervalMap::const_iterator : public std::iterator { protected: friend class IntervalMap; - typedef std::pair PathEntry; - typedef SmallVector Path; // The map referred to. IntervalMap *map; - // The offset into map's root node. - unsigned rootOffset; - // We store a full path from the root to the current position. - // - // When rootOffset == map->rootSize, we are at end() and path() is empty. - // Otherwise, when branched these conditions hold: - // - // 1. path.front().first == rootBranch().subtree(rootOffset) - // 2. path[i].first == path[i-1].first.subtree(path[i-1].second) - // 3. path.size() == map->height. - // - // Thus, path.back() always refers to the current leaf node unless the root is - // unbranched. - // // The path may be partially filled, but never between iterator calls. - Path path; + IntervalMapImpl::Path path; - explicit const_iterator(IntervalMap &map) - : map(&map), rootOffset(map.rootSize) {} + explicit const_iterator(IntervalMap &map) : map(&map) {} bool branched() const { assert(map && "Invalid iterator"); return map->branched(); } - IntervalMapImpl::NodeRef pathNode(unsigned h) const { return path[h].first; } - IntervalMapImpl::NodeRef &pathNode(unsigned h) { return path[h].first; } - unsigned pathOffset(unsigned h) const { return path[h].second; } - unsigned &pathOffset(unsigned h) { return path[h].second; } - - Leaf &treeLeaf() const { - assert(branched() && path.size() == map->height); - return path.back().first.template get(); - } - unsigned treeLeafSize() const { - assert(branched() && path.size() == map->height); - return path.back().first.size(); - } - unsigned &treeLeafOffset() { - assert(branched() && path.size() == map->height); - return path.back().second; - } - unsigned treeLeafOffset() const { - assert(branched() && path.size() == map->height); - return path.back().second; - } - - // Get the next node ptr for an incomplete path. - IntervalMapImpl::NodeRef pathNextDown() { - assert(path.size() < map->height && "Path is already complete"); - - if (path.empty()) - return map->rootBranch().subtree(rootOffset); + void setRoot(unsigned Offset) { + if (branched()) + path.setRoot(&map->rootBranch(), map->rootSize, Offset); else - return path.back().first.subtree(path.back().second); + path.setRoot(&map->rootLeaf(), map->rootSize, Offset); } - void pathFillLeft(); void pathFillFind(KeyT x); - void pathFillRight(); - - IntervalMapImpl::NodeRef leftSibling(unsigned level) const; - IntervalMapImpl::NodeRef rightSibling(unsigned level) const; - - void treeIncrement(); - void treeDecrement(); void treeFind(KeyT x); public: /// valid - Return true if the current position is valid, false for end(). - bool valid() const { - assert(map && "Invalid iterator"); - return rootOffset < map->rootSize; - } + bool valid() const { return path.valid(); } /// start - Return the beginning of the current interval. const KeyT &start() const { assert(valid() && "Cannot access invalid iterator"); - return branched() ? treeLeaf().start(treeLeafOffset()) : - map->rootLeaf().start(rootOffset); + return branched() ? path.leaf().start(path.leafOffset()) : + path.leaf().start(path.leafOffset()); } /// stop - Return the end of the current interval. const KeyT &stop() const { assert(valid() && "Cannot access invalid iterator"); - return branched() ? treeLeaf().stop(treeLeafOffset()) : - map->rootLeaf().stop(rootOffset); + return branched() ? path.leaf().stop(path.leafOffset()) : + path.leaf().stop(path.leafOffset()); } /// value - Return the mapped value at the current interval. const ValT &value() const { assert(valid() && "Cannot access invalid iterator"); - return branched() ? treeLeaf().value(treeLeafOffset()) : - map->rootLeaf().value(rootOffset); + return branched() ? path.leaf().value(path.leafOffset()) : + path.leaf().value(path.leafOffset()); } const ValT &operator*() const { @@ -1212,8 +1314,11 @@ public: bool operator==(const const_iterator &RHS) const { assert(map == RHS.map && "Cannot compare iterators from different maps"); - return rootOffset == RHS.rootOffset && - (!valid() || !branched() || path.back() == RHS.path.back()); + if (!valid()) + return !RHS.valid(); + if (path.leafOffset() != RHS.path.leafOffset()) + return false; + return &path.template leaf() == &RHS.path.template leaf(); } bool operator!=(const const_iterator &RHS) const { @@ -1222,27 +1327,21 @@ public: /// goToBegin - Move to the first interval in map. void goToBegin() { - rootOffset = 0; - path.clear(); + setRoot(0); if (branched()) - pathFillLeft(); + path.fillLeft(map->height); } /// goToEnd - Move beyond the last interval in map. void goToEnd() { - rootOffset = map->rootSize; - path.clear(); + setRoot(map->rootSize); } /// preincrement - move to the next interval. const_iterator &operator++() { assert(valid() && "Cannot increment end()"); - if (!branched()) - ++rootOffset; - else if (treeLeafOffset() != treeLeafSize() - 1) - ++treeLeafOffset(); - else - treeIncrement(); + if (++path.leafOffset() == path.leafSize() && branched()) + path.moveRight(map->height); return *this; } @@ -1255,13 +1354,10 @@ public: /// predecrement - move to the previous interval. const_iterator &operator--() { - if (!branched()) { - assert(rootOffset && "Cannot decrement begin()"); - --rootOffset; - } else if (valid() && treeLeafOffset()) - --treeLeafOffset(); + if (path.leafOffset() && (valid() || !branched())) + --path.leafOffset(); else - treeDecrement(); + path.moveLeft(map->height); return *this; } @@ -1278,7 +1374,7 @@ public: if (branched()) treeFind(x); else - rootOffset = map->rootLeaf().findFrom(0, map->rootSize, x); + setRoot(map->rootLeaf().findFrom(0, map->rootSize, x)); } /// advanceTo - Move to the first interval with stop >= x, or end(). @@ -1288,150 +1384,30 @@ public: if (branched()) treeAdvanceTo(x); else - rootOffset = map->rootLeaf().findFrom(rootOffset, map->rootSize, x); + path.leafOffset() = + map->rootLeaf().findFrom(path.leafOffset(), map->rootSize, x); } }; -// pathFillLeft - Complete path by following left-most branches. -template -void IntervalMap:: -const_iterator::pathFillLeft() { - IntervalMapImpl::NodeRef NR = pathNextDown(); - for (unsigned i = map->height - path.size() - 1; i; --i) { - path.push_back(PathEntry(NR, 0)); - NR = NR.subtree(0); - } - path.push_back(PathEntry(NR, 0)); -} - // pathFillFind - Complete path by searching for x. template void IntervalMap:: const_iterator::pathFillFind(KeyT x) { - IntervalMapImpl::NodeRef NR = pathNextDown(); - for (unsigned i = map->height - path.size() - 1; i; --i) { + IntervalMapImpl::NodeRef NR = path.subtree(path.height()); + for (unsigned i = map->height - path.height() - 1; i; --i) { unsigned p = NR.get().safeFind(0, x); - path.push_back(PathEntry(NR, p)); + path.push(NR, p); NR = NR.subtree(p); } - path.push_back(PathEntry(NR, NR.get().safeFind(0, x))); -} - -// pathFillRight - Complete path by adding rightmost entries. -template -void IntervalMap:: -const_iterator::pathFillRight() { - IntervalMapImpl::NodeRef NR = pathNextDown(); - for (unsigned i = map->height - path.size() - 1; i; --i) { - unsigned p = NR.size() - 1; - path.push_back(PathEntry(NR, p)); - NR = NR.subtree(p); - } - path.push_back(PathEntry(NR, NR.size() - 1)); -} - -/// leftSibling - find the left sibling node to path[level]. -/// @param level 0 is just below the root, map->height - 1 for the leaves. -/// @return The left sibling NodeRef, or NULL. -template -IntervalMapImpl::NodeRef IntervalMap:: -const_iterator::leftSibling(unsigned level) const { - using namespace IntervalMapImpl; - assert(branched() && "Not at a branched node"); - assert(level <= path.size() && "Bad level"); - - // Go up the tree until we can go left. - unsigned h = level; - while (h && pathOffset(h - 1) == 0) - --h; - - // We are at the first leaf node, no left sibling. - if (!h && rootOffset == 0) - return NodeRef(); - - // NR is the subtree containing our left sibling. - NodeRef NR = h ? - pathNode(h - 1).subtree(pathOffset(h - 1) - 1) : - map->rootBranch().subtree(rootOffset - 1); - - // Keep right all the way down. - for (; h != level; ++h) - NR = NR.subtree(NR.size() - 1); - return NR; -} - -/// rightSibling - find the right sibling node to path[level]. -/// @param level 0 is just below the root, map->height - 1 for the leaves. -/// @return The right sibling NodeRef, or NULL. -template -IntervalMapImpl::NodeRef IntervalMap:: -const_iterator::rightSibling(unsigned level) const { - using namespace IntervalMapImpl; - assert(branched() && "Not at a branched node"); - assert(level <= this->path.size() && "Bad level"); - - // Go up the tree until we can go right. - unsigned h = level; - while (h && pathOffset(h - 1) == pathNode(h - 1).size() - 1) - --h; - - // We are at the last leaf node, no right sibling. - if (!h && rootOffset == map->rootSize - 1) - return NodeRef(); - - // NR is the subtree containing our right sibling. - NodeRef NR = h ? - pathNode(h - 1).subtree(pathOffset(h - 1) + 1) : - map->rootBranch().subtree(rootOffset + 1); - - // Keep left all the way down. - for (; h != level; ++h) - NR = NR.subtree(0); - return NR; -} - -// treeIncrement - Move to the beginning of the next leaf node. -template -void IntervalMap:: -const_iterator::treeIncrement() { - assert(branched() && "treeIncrement is not for small maps"); - assert(path.size() == map->height && "inconsistent iterator"); - do path.pop_back(); - while (!path.empty() && path.back().second == path.back().first.size() - 1); - if (path.empty()) { - ++rootOffset; - if (!valid()) - return; - } else - ++path.back().second; - pathFillLeft(); -} - -// treeDecrement - Move to the end of the previous leaf node. -template -void IntervalMap:: -const_iterator::treeDecrement() { - assert(branched() && "treeDecrement is not for small maps"); - if (valid()) { - assert(path.size() == map->height && "inconsistent iterator"); - do path.pop_back(); - while (!path.empty() && path.back().second == 0); - } - if (path.empty()) { - assert(rootOffset && "cannot treeDecrement() on begin()"); - --rootOffset; - } else - --path.back().second; - pathFillRight(); + path.push(NR, NR.get().safeFind(0, x)); } // treeFind - Find in a branched tree. template void IntervalMap:: const_iterator::treeFind(KeyT x) { - path.clear(); - rootOffset = map->rootBranch().findFrom(0, map->rootSize, x); + setRoot(map->rootBranch().findFrom(0, map->rootSize, x)); if (valid()) pathFillFind(x); } @@ -1488,7 +1464,6 @@ class IntervalMap::iterator : public const_iterator { explicit iterator(IntervalMap &map) : const_iterator(map) {} - void setNodeSize(unsigned Level, unsigned Size); void setNodeStop(unsigned Level, KeyT Stop); bool insertNode(unsigned Level, IntervalMapImpl::NodeRef Node, KeyT Stop); template bool overflow(unsigned Level); @@ -1500,31 +1475,22 @@ public: }; -/// setNodeSize - Set the size of the node at path[level], updating both path -/// and the real tree. -/// @param level 0 is just below the root, map->height - 1 for the leaves. -/// @param size New node size. -template -void IntervalMap:: -iterator::setNodeSize(unsigned Level, unsigned Size) { - this->pathNode(Level).setSize(Size); - if (Level) - this->pathNode(Level-1).subtree(this->pathOffset(Level-1)).setSize(Size); - else - this->map->rootBranch().subtree(this->rootOffset).setSize(Size); -} - /// setNodeStop - Update the stop key of the current node at level and above. template void IntervalMap:: iterator::setNodeStop(unsigned Level, KeyT Stop) { - while (Level--) { - this->pathNode(Level).template get() - .stop(this->pathOffset(Level)) = Stop; - if (this->pathOffset(Level) != this->pathNode(Level).size() - 1) + // There are no references to the root node, so nothing to update. + if (!Level) + return; + IntervalMapImpl::Path &P = this->path; + // Update nodes pointing to the current node. + while (--Level) { + P.node(Level).stop(P.offset(Level)) = Stop; + if (!P.atLastBranch(Level)) return; } - this->map->rootBranch().stop(this->rootOffset) = Stop; + // Update root separately since it has a different layout. + P.node(Level).stop(P.offset(Level)) = Stop; } /// insertNode - insert a node before the current path at level. @@ -1536,42 +1502,40 @@ iterator::setNodeStop(unsigned Level, KeyT Stop) { template bool IntervalMap:: iterator::insertNode(unsigned Level, IntervalMapImpl::NodeRef Node, KeyT Stop) { + assert(Level && "Cannot insert next to the root"); bool SplitRoot = false; + IntervalMap &IM = *this->map; + IntervalMapImpl::Path &P = this->path; - if (!Level) { + if (Level == 1) { // Insert into the root branch node. - IntervalMap &IM = *this->map; if (IM.rootSize < RootBranch::Capacity) { - IM.rootBranch().insert(this->rootOffset, IM.rootSize, Node, Stop); - ++IM.rootSize; + IM.rootBranch().insert(P.offset(0), IM.rootSize, Node, Stop); + P.setSize(0, ++IM.rootSize); return SplitRoot; } // We need to split the root while keeping our position. SplitRoot = true; - IdxPair Offset = IM.splitRoot(this->rootOffset); - this->rootOffset = Offset.first; - this->path.insert(this->path.begin(),std::make_pair( - this->map->rootBranch().subtree(Offset.first), Offset.second)); - Level = 1; + IdxPair Offset = IM.splitRoot(P.offset(0)); + P.replaceRoot(&IM.rootBranch(), IM.rootSize, Offset); + + // Fall through to insert at the new higher level. + ++Level; } // When inserting before end(), make sure we have a valid path. - if (!this->valid()) { - this->treeDecrement(); - ++this->pathOffset(Level-1); - } + P.legalizeForInsert(--Level); - // Insert into the branch node at level-1. - if (this->pathNode(Level-1).size() == Branch::Capacity) { + // Insert into the branch node at Level-1. + if (P.size(Level) == Branch::Capacity) { + // Branch node is full, handle handle the overflow. assert(!SplitRoot && "Cannot overflow after splitting the root"); - SplitRoot = overflow(Level - 1); + SplitRoot = overflow(Level); Level += SplitRoot; } - IntervalMapImpl::NodeRef NR = this->pathNode(Level-1); - unsigned Offset = this->pathOffset(Level-1); - NR.get().insert(Offset, NR.size(), Node, Stop); - setNodeSize(Level - 1, NR.size() + 1); + P.node(Level).insert(P.offset(Level), P.size(Level), Node, Stop); + P.setSize(Level, P.size(Level) + 1); return SplitRoot; } @@ -1581,18 +1545,24 @@ void IntervalMap:: iterator::insert(KeyT a, KeyT b, ValT y) { if (this->branched()) return treeInsert(a, b, y); - IdxPair IP = this->map->rootLeaf().insertFrom(this->rootOffset, - this->map->rootSize, - a, b, y); + IntervalMap &IM = *this->map; + IntervalMapImpl::Path &P = this->path; + + // Try simple root leaf insert. + IdxPair IP = IM.rootLeaf().insertFrom(P.leafOffset(), IM.rootSize, a, b, y); + + // Was the root node insert successful? if (IP.second <= RootLeaf::Capacity) { - this->rootOffset = IP.first; - this->map->rootSize = IP.second; + P.leafOffset() = IP.first; + P.setSize(0, IM.rootSize = IP.second); return; } - IdxPair Offset = this->map->branchRoot(this->rootOffset); - this->rootOffset = Offset.first; - this->path.push_back(std::make_pair( - this->map->rootBranch().subtree(Offset.first), Offset.second)); + + // Root leaf node is full, we must branch. + IdxPair Offset = IM.branchRoot(P.leafOffset()); + P.replaceRoot(&IM.rootBranch(), IM.rootSize, Offset); + + // Now it fits in the new leaf. treeInsert(a, b, y); } @@ -1600,29 +1570,26 @@ iterator::insert(KeyT a, KeyT b, ValT y) { template void IntervalMap:: iterator::treeInsert(KeyT a, KeyT b, ValT y) { - if (!this->valid()) { - // end() has an empty path. Go back to the last leaf node and use an - // invalid offset instead. - this->treeDecrement(); - ++this->treeLeafOffset(); + IntervalMap &IM = *this->map; + IntervalMapImpl::Path &P = this->path; + + P.legalizeForInsert(IM.height); + IdxPair IP = P.leaf().insertFrom(P.leafOffset(), P.leafSize(), a, b, y); + + // Leaf insertion unsuccessful? Overflow and try again. + if (IP.second > Leaf::Capacity) { + overflow(IM.height); + IP = P.leaf().insertFrom(P.leafOffset(), P.leafSize(), a, b, y); + assert(IP.second <= Leaf::Capacity && "overflow() didn't make room"); } - IdxPair IP = this->treeLeaf().insertFrom(this->treeLeafOffset(), - this->treeLeafSize(), a, b, y); - this->treeLeafOffset() = IP.first; - if (IP.second <= Leaf::Capacity) { - setNodeSize(this->map->height - 1, IP.second); - if (IP.first == IP.second - 1) - setNodeStop(this->map->height - 1, this->treeLeaf().stop(IP.first)); - return; - } - // Leaf node has no space. - overflow(this->map->height - 1); - IP = this->treeLeaf().insertFrom(this->treeLeafOffset(), - this->treeLeafSize(), a, b, y); - this->treeLeafOffset() = IP.first; - setNodeSize(this->map->height-1, IP.second); + + // Inserted, update offset and leaf size. + P.leafOffset() = IP.first; + P.setSize(IM.height, IP.second); + + // Insert was the last node entry, update stops. if (IP.first == IP.second - 1) - setNodeStop(this->map->height - 1, this->treeLeaf().stop(IP.first)); + setNodeStop(IM.height, P.leaf().stop(IP.first)); // FIXME: Handle cross-node coalescing. } @@ -1638,26 +1605,26 @@ template bool IntervalMap:: iterator::overflow(unsigned Level) { using namespace IntervalMapImpl; + Path &P = this->path; unsigned CurSize[4]; NodeT *Node[4]; unsigned Nodes = 0; unsigned Elements = 0; - unsigned Offset = this->pathOffset(Level); + unsigned Offset = P.offset(Level); // Do we have a left sibling? - NodeRef LeftSib = this->leftSibling(Level); + NodeRef LeftSib = P.getLeftSibling(Level); if (LeftSib) { Offset += Elements = CurSize[Nodes] = LeftSib.size(); Node[Nodes++] = &LeftSib.get(); } // Current node. - NodeRef CurNode = this->pathNode(Level); - Elements += CurSize[Nodes] = CurNode.size(); - Node[Nodes++] = &CurNode.get(); + Elements += CurSize[Nodes] = P.size(Level); + Node[Nodes++] = &P.node(Level); // Do we have a right sibling? - NodeRef RightSib = this->rightSibling(Level); + NodeRef RightSib = P.getRightSibling(Level); if (RightSib) { Offset += Elements = CurSize[Nodes] = RightSib.size(); Node[Nodes++] = &RightSib.get(); @@ -1682,7 +1649,7 @@ iterator::overflow(unsigned Level) { // Move current location to the leftmost node. if (LeftSib) - this->treeDecrement(); + P.moveLeft(Level); // Move elements right. for (int n = Nodes - 1; n; --n) { @@ -1728,21 +1695,21 @@ iterator::overflow(unsigned Level) { SplitRoot = insertNode(Level, NodeRef(Node[Pos], NewSize[Pos]), Stop); Level += SplitRoot; } else { - setNodeSize(Level, NewSize[Pos]); + P.setSize(Level, NewSize[Pos]); setNodeStop(Level, Stop); } if (Pos + 1 == Nodes) break; - this->treeIncrement(); + P.moveRight(Level); ++Pos; } // Where was I? Find NewOffset. while(Pos != NewOffset.first) { - this->treeDecrement(); + P.moveLeft(Level); --Pos; } - this->pathOffset(Level) = NewOffset.second; + P.offset(Level) = NewOffset.second; return SplitRoot; } diff --git a/lib/Support/IntervalMap.cpp b/lib/Support/IntervalMap.cpp index 9f5c72fef1c..6f39b183a1c 100644 --- a/lib/Support/IntervalMap.cpp +++ b/lib/Support/IntervalMap.cpp @@ -16,6 +16,107 @@ namespace llvm { namespace IntervalMapImpl { +void Path::replaceRoot(void *Root, unsigned Size, IdxPair Offsets) { + assert(!path.empty() && "Can't replace missing root"); + path.front() = Entry(Root, Size, Offsets.first); + path.insert(path.begin() + 1, Entry(subtree(0), Offsets.second)); +} + +NodeRef Path::getLeftSibling(unsigned Level) const { + // The root has no siblings. + if (Level == 0) + return NodeRef(); + + // Go up the tree until we can go left. + unsigned l = Level - 1; + while (l && path[l].offset == 0) + --l; + + // We can't go left. + if (path[l].offset == 0) + return NodeRef(); + + // NR is the subtree containing our left sibling. + NodeRef NR = path[l].subtree(path[l].offset - 1); + + // Keep right all the way down. + for (++l; l != Level; ++l) + NR = NR.subtree(NR.size() - 1); + return NR; +} + +void Path::moveLeft(unsigned Level) { + assert(Level != 0 && "Cannot move the root node"); + + // Go up the tree until we can go left. + unsigned l = 0; + if (valid()) { + l = Level - 1; + while (path[l].offset == 0) { + assert(l != 0 && "Cannot move beyond begin()"); + --l; + } + } else if (height() < Level) + // end() may have created a height=0 path. + path.resize(Level + 1, Entry(0, 0, 0)); + + // NR is the subtree containing our left sibling. + --path[l].offset; + NodeRef NR = subtree(l); + + // Get the rightmost node in the subtree. + for (++l; l != Level; ++l) { + path[l] = Entry(NR, NR.size() - 1); + NR = NR.subtree(NR.size() - 1); + } + path[l] = Entry(NR, NR.size() - 1); +} + +NodeRef Path::getRightSibling(unsigned Level) const { + // The root has no siblings. + if (Level == 0) + return NodeRef(); + + // Go up the tree until we can go right. + unsigned l = Level - 1; + while (l && atLastBranch(l)) + --l; + + // We can't go right. + if (atLastBranch(l)) + return NodeRef(); + + // NR is the subtree containing our right sibling. + NodeRef NR = path[l].subtree(path[l].offset + 1); + + // Keep left all the way down. + for (++l; l != Level; ++l) + NR = NR.subtree(0); + return NR; +} + +void Path::moveRight(unsigned Level) { + assert(Level != 0 && "Cannot move the root node"); + + // Go up the tree until we can go right. + unsigned l = Level - 1; + while (l && atLastBranch(l)) + --l; + + // NR is the subtree containing our right sibling. If we hit end(), we have + // offset(0) == node(0).size(). + if (++path[l].offset == path[l].size) + return; + NodeRef NR = subtree(l); + + for (++l; l != Level; ++l) { + path[l] = Entry(NR, 0); + NR = NR.subtree(0); + } + path[l] = Entry(NR, 0); +} + + IdxPair distribute(unsigned Nodes, unsigned Elements, unsigned Capacity, const unsigned *CurSize, unsigned NewSize[], unsigned Position, bool Grow) { @@ -56,5 +157,5 @@ IdxPair distribute(unsigned Nodes, unsigned Elements, unsigned Capacity, } } // namespace IntervalMapImpl -} // namespace llvm +} // namespace llvm