[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