summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorJakob Stoklund Olesen <stoklund@2pi.dk>2010-11-26 01:39:40 +0000
committerJakob Stoklund Olesen <stoklund@2pi.dk>2010-11-26 01:39:40 +0000
commit706da9d8ca207c93d38855ffd96cf9722996d706 (patch)
tree2815436548f89425b7599ae825d03d425809c18b /include
parent20a00c4f80b69494129d2533f55c7d7b2f657266 (diff)
downloadllvm-706da9d8ca207c93d38855ffd96cf9722996d706.tar.gz
llvm-706da9d8ca207c93d38855ffd96cf9722996d706.tar.bz2
llvm-706da9d8ca207c93d38855ffd96cf9722996d706.tar.xz
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.) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120165 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include')
-rw-r--r--include/llvm/ADT/IntervalMap.h557
1 files changed, 262 insertions, 295 deletions
diff --git a/include/llvm/ADT/IntervalMap.h b/include/llvm/ADT/IntervalMap.h
index 314af50923..b571b95209 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<NodeRef*>(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<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 @@ class IntervalMap<KeyT, ValT, N, Traits>::const_iterator :
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 @@ 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<Leaf>() == &RHS.path.template leaf<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 <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 @@ class IntervalMap<KeyT, ValT, N, Traits>::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 <typename NodeT> 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 <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 @@ iterator::setNodeStop(unsigned Level, KeyT Stop) {
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 @@ void IntervalMap<KeyT, ValT, N, Traits>::
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 <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 @@ template <typename NodeT>
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 @@ 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;
}