[llvm-commits] [llvm] r120165 - in /llvm/trunk: include/llvm/ADT/IntervalMap.h lib/Support/IntervalMap.cpp
Jakob Stoklund Olesen
stoklund at 2pi.dk
Thu Nov 25 17:39:40 PST 2010
Author: stoklund
Date: Thu Nov 25 19:39:40 2010
New Revision: 120165
URL: http://llvm.org/viewvc/llvm-project?rev=120165&view=rev
Log:
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.)
Modified:
llvm/trunk/include/llvm/ADT/IntervalMap.h
llvm/trunk/lib/Support/IntervalMap.cpp
Modified: llvm/trunk/include/llvm/ADT/IntervalMap.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/IntervalMap.h?rev=120165&r1=120164&r2=120165&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/IntervalMap.h (original)
+++ llvm/trunk/include/llvm/ADT/IntervalMap.h Thu Nov 25 19:39:40 2010
@@ -403,7 +403,7 @@
/// 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<NodeRef*>(pip.getPointer())[i];
}
@@ -699,6 +699,161 @@
};
+//===----------------------------------------------------------------------===//
+//--- 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<NodeRef*>(node)[i];
+ }
+ };
+
+ /// path - The path entries, path[0] is the root node, path.back() is a leaf.
+ SmallVector<Entry, 4> path;
+
+public:
+ // Node accessors.
+ template <typename NodeT> NodeT &node(unsigned Level) const {
+ return *reinterpret_cast<NodeT*>(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 <typename NodeT> NodeT &leaf() const {
+ return *reinterpret_cast<NodeT*>(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 @@
public std::iterator<std::bidirectional_iterator_tag, ValT> {
protected:
friend class IntervalMap;
- typedef std::pair<IntervalMapImpl::NodeRef, unsigned> PathEntry;
- typedef SmallVector<PathEntry, 4> 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<Leaf>();
- }
- 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<Leaf>().start(path.leafOffset()) :
+ path.leaf<RootLeaf>().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<Leaf>().stop(path.leafOffset()) :
+ path.leaf<RootLeaf>().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<Leaf>().value(path.leafOffset()) :
+ path.leaf<RootLeaf>().value(path.leafOffset());
}
const ValT &operator*() const {
@@ -1212,8 +1314,11 @@
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<Leaf>() == &RHS.path.template leaf<Leaf>();
}
bool operator!=(const const_iterator &RHS) const {
@@ -1222,27 +1327,21 @@
/// 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 @@
/// 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 @@
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 @@
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 <typename KeyT, typename ValT, unsigned N, typename Traits>
-void IntervalMap<KeyT, ValT, N, Traits>::
-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 <typename KeyT, typename ValT, unsigned N, typename Traits>
void IntervalMap<KeyT, ValT, N, Traits>::
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<Branch>().safeFind(0, x);
- path.push_back(PathEntry(NR, p));
- NR = NR.subtree(p);
- }
- path.push_back(PathEntry(NR, NR.get<Leaf>().safeFind(0, x)));
-}
-
-// pathFillRight - Complete path by adding rightmost entries.
-template <typename KeyT, typename ValT, unsigned N, typename Traits>
-void IntervalMap<KeyT, ValT, N, Traits>::
-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));
+ path.push(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 <typename KeyT, typename ValT, unsigned N, typename Traits>
-IntervalMapImpl::NodeRef IntervalMap<KeyT, ValT, N, Traits>::
-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 <typename KeyT, typename ValT, unsigned N, typename Traits>
-IntervalMapImpl::NodeRef IntervalMap<KeyT, ValT, N, Traits>::
-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 <typename KeyT, typename ValT, unsigned N, typename Traits>
-void IntervalMap<KeyT, ValT, N, Traits>::
-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 <typename KeyT, typename ValT, unsigned N, typename Traits>
-void IntervalMap<KeyT, ValT, N, Traits>::
-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<Leaf>().safeFind(0, x));
}
// treeFind - Find in a branched tree.
template <typename KeyT, typename ValT, unsigned N, typename Traits>
void IntervalMap<KeyT, ValT, N, Traits>::
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 @@
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 <typename NodeT> bool overflow(unsigned Level);
@@ -1500,31 +1475,22 @@
};
-/// 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 <typename KeyT, typename ValT, unsigned N, typename Traits>
-void IntervalMap<KeyT, ValT, N, Traits>::
-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 <typename KeyT, typename ValT, unsigned N, typename Traits>
void IntervalMap<KeyT, ValT, N, Traits>::
iterator::setNodeStop(unsigned Level, KeyT Stop) {
- while (Level--) {
- this->pathNode(Level).template get<Branch>()
- .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<Branch>(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<RootBranch>(Level).stop(P.offset(Level)) = Stop;
}
/// insertNode - insert a node before the current path at level.
@@ -1536,42 +1502,40 @@
template <typename KeyT, typename ValT, unsigned N, typename Traits>
bool IntervalMap<KeyT, ValT, N, Traits>::
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<Branch>(Level - 1);
+ SplitRoot = overflow<Branch>(Level);
Level += SplitRoot;
}
- IntervalMapImpl::NodeRef NR = this->pathNode(Level-1);
- unsigned Offset = this->pathOffset(Level-1);
- NR.get<Branch>().insert(Offset, NR.size(), Node, Stop);
- setNodeSize(Level - 1, NR.size() + 1);
+ P.node<Branch>(Level).insert(P.offset(Level), P.size(Level), Node, Stop);
+ P.setSize(Level, P.size(Level) + 1);
return SplitRoot;
}
@@ -1581,18 +1545,24 @@
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 @@
template <typename KeyT, typename ValT, unsigned N, typename Traits>
void IntervalMap<KeyT, ValT, N, Traits>::
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();
- }
- 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;
+ IntervalMap &IM = *this->map;
+ IntervalMapImpl::Path &P = this->path;
+
+ P.legalizeForInsert(IM.height);
+ IdxPair IP = P.leaf<Leaf>().insertFrom(P.leafOffset(), P.leafSize(), a, b, y);
+
+ // Leaf insertion unsuccessful? Overflow and try again.
+ if (IP.second > Leaf::Capacity) {
+ overflow<Leaf>(IM.height);
+ IP = P.leaf<Leaf>().insertFrom(P.leafOffset(), P.leafSize(), a, b, y);
+ assert(IP.second <= Leaf::Capacity && "overflow() didn't make room");
}
- // Leaf node has no space.
- overflow<Leaf>(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<Leaf>().stop(IP.first));
// FIXME: Handle cross-node coalescing.
}
@@ -1638,26 +1605,26 @@
bool IntervalMap<KeyT, ValT, N, Traits>::
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<NodeT>();
}
// Current node.
- NodeRef CurNode = this->pathNode(Level);
- Elements += CurSize[Nodes] = CurNode.size();
- Node[Nodes++] = &CurNode.get<NodeT>();
+ Elements += CurSize[Nodes] = P.size(Level);
+ Node[Nodes++] = &P.node<NodeT>(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<NodeT>();
@@ -1682,7 +1649,7 @@
// 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 @@
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;
}
Modified: llvm/trunk/lib/Support/IntervalMap.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/IntervalMap.cpp?rev=120165&r1=120164&r2=120165&view=diff
==============================================================================
--- llvm/trunk/lib/Support/IntervalMap.cpp (original)
+++ llvm/trunk/lib/Support/IntervalMap.cpp Thu Nov 25 19:39:40 2010
@@ -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 @@
}
} // namespace IntervalMapImpl
-} // namespace llvm
+} // namespace llvm
More information about the llvm-commits
mailing list