diff --git a/include/llvm/ADT/IntervalMap.h b/include/llvm/ADT/IntervalMap.h index 8416f71b7f5..d0a3b53087d 100644 --- a/include/llvm/ADT/IntervalMap.h +++ b/include/llvm/ADT/IntervalMap.h @@ -586,8 +586,7 @@ public: return Traits::startLess(x, start(i)) ? NotFound : value(i); } - IdxPair insertFrom(unsigned i, unsigned Size, KeyT a, KeyT b, ValT y); - unsigned extendStop(unsigned i, unsigned Size, KeyT b); + unsigned insertFrom(unsigned &Pos, unsigned Size, KeyT a, KeyT b, ValT y); #ifndef NDEBUG void dump(raw_ostream &OS, unsigned Size) { @@ -610,91 +609,58 @@ public: /// @param y Value be mapped. /// @return (insert position, new size), or (i, Capacity+1) on overflow. template -IdxPair LeafNode:: -insertFrom(unsigned i, unsigned Size, KeyT a, KeyT b, ValT y) { +unsigned LeafNode:: +insertFrom(unsigned &Pos, unsigned Size, KeyT a, KeyT b, ValT y) { + unsigned i = Pos; assert(i <= Size && Size <= N && "Invalid index"); assert(!Traits::stopLess(b, a) && "Invalid interval"); // Verify the findFrom invariant. assert((i == 0 || Traits::stopLess(stop(i - 1), a))); assert((i == Size || !Traits::stopLess(stop(i), a))); + assert((i == Size || Traits::stopLess(b, start(i))) && "Overlapping insert"); // Coalesce with previous interval. - if (i && value(i - 1) == y && Traits::adjacent(stop(i - 1), a)) - return IdxPair(i - 1, extendStop(i - 1, Size, b)); + if (i && value(i - 1) == y && Traits::adjacent(stop(i - 1), a)) { + Pos = i - 1; + // Also coalesce with next interval? + if (i != Size && value(i) == y && Traits::adjacent(b, start(i))) { + stop(i - 1) = stop(i); + this->erase(i, Size); + return Size - 1; + } + stop(i - 1) = b; + return Size; + } // Detect overflow. if (i == N) - return IdxPair(i, N + 1); + return N + 1; // Add new interval at end. if (i == Size) { start(i) = a; stop(i) = b; value(i) = y; - return IdxPair(i, Size + 1); - } - - // Overlapping intervals? - if (!Traits::stopLess(b, start(i))) { - assert(value(i) == y && "Inconsistent values in overlapping intervals"); - if (Traits::startLess(a, start(i))) - start(i) = a; - return IdxPair(i, extendStop(i, Size, b)); + return Size + 1; } // Try to coalesce with following interval. if (value(i) == y && Traits::adjacent(b, start(i))) { start(i) = a; - return IdxPair(i, Size); + return Size; } // We must insert before i. Detect overflow. if (Size == N) - return IdxPair(i, N + 1); + return N + 1; // Insert before i. this->shift(i, Size); start(i) = a; stop(i) = b; value(i) = y; - return IdxPair(i, Size + 1); -} - -/// extendStop - Extend stop(i) to b, coalescing with following intervals. -/// @param i Interval to extend. -/// @param Size Number of elements in node. -/// @param b New interval end point. -/// @return New node size after coalescing. -template -unsigned LeafNode:: -extendStop(unsigned i, unsigned Size, KeyT b) { - assert(i < Size && Size <= N && "Bad indices"); - - // Are we even extending the interval? - if (Traits::startLess(b, stop(i))) - return Size; - - // Find the first interval that may be preserved. - unsigned j = findFrom(i + 1, Size, b); - if (j < Size) { - // Would key[i] overlap key[j] after the extension? - if (Traits::stopLess(b, start(j))) { - // Not overlapping. Perhaps adjacent and coalescable? - if (value(i) == value(j) && Traits::adjacent(b, start(j))) - b = stop(j++); - } else { - // Overlap. Include key[j] in the new interval. - assert(value(i) == value(j) && "Overlapping values"); - b = stop(j++); - } - } - stop(i) = b; - - // Entries [i+1;j) were coalesced. - if (i + 1 < j && j < Size) - this->erase(i + 1, j, Size); - return Size - (j - (i + 1)); + return Size + 1; } @@ -1138,7 +1104,7 @@ public: // Easy insert into root leaf. unsigned p = rootLeaf().findFrom(0, rootSize, a); - rootSize = rootLeaf().insertFrom(p, rootSize, a, b, y).second; + rootSize = rootLeaf().insertFrom(p, rootSize, a, b, y); } /// clear - Remove all entries. @@ -1697,12 +1663,11 @@ iterator::insert(KeyT a, KeyT b, ValT y) { IntervalMapImpl::Path &P = this->path; // Try simple root leaf insert. - IdxPair IP = IM.rootLeaf().insertFrom(P.leafOffset(), IM.rootSize, a, b, y); + unsigned Size = IM.rootLeaf().insertFrom(P.leafOffset(), IM.rootSize, a, b, y); // Was the root node insert successful? - if (IP.second <= RootLeaf::Capacity) { - P.leafOffset() = IP.first; - P.setSize(0, IM.rootSize = IP.second); + if (Size <= RootLeaf::Capacity) { + P.setSize(0, IM.rootSize = Size); return; } @@ -1719,14 +1684,15 @@ template void IntervalMap:: iterator::treeInsert(KeyT a, KeyT b, ValT y) { using namespace IntervalMapImpl; - IntervalMap &IM = *this->map; Path &P = this->path; + if (!P.valid()) + P.legalizeForInsert(this->map->height); + // Check if this insertion will extend the node to the left. - if (P.valid() && P.leafOffset() == 0 && - Traits::startLess(a, P.leaf().start(0))) { + if (P.leafOffset() == 0 && Traits::startLess(a, P.leaf().start(0))) { // Node is growing to the left, will it affect a left sibling node? - if (NodeRef Sib = P.getLeftSibling(IM.height)) { + if (NodeRef Sib = P.getLeftSibling(P.height())) { Leaf &SibLeaf = Sib.get(); unsigned SibOfs = Sib.size() - 1; if (SibLeaf.value(SibOfs) == y && @@ -1737,11 +1703,11 @@ iterator::treeInsert(KeyT a, KeyT b, ValT y) { // 2. Extend a to SibLeaf, erase the SibLeaf entry and continue. // We prefer 1., but need 2 when coalescing to the right as well. Leaf &CurLeaf = P.leaf(); - P.moveLeft(IM.height); + P.moveLeft(P.height()); if (Traits::stopLess(b, CurLeaf.start(0)) && (y != CurLeaf.value(0) || !Traits::adjacent(b, CurLeaf.start(0)))) { // Easy, just extend SibLeaf and we're done. - setNodeStop(IM.height, SibLeaf.stop(SibOfs) = b); + setNodeStop(P.height(), SibLeaf.stop(SibOfs) = b); return; } else { // We have both left and right coalescing. Erase the old SibLeaf entry @@ -1752,27 +1718,29 @@ iterator::treeInsert(KeyT a, KeyT b, ValT y) { } } else { // No left sibling means we are at begin(). Update cached bound. - IM.rootBranchStart() = a; + this->map->rootBranchStart() = a; } } - P.legalizeForInsert(IM.height); - IdxPair IP = P.leaf().insertFrom(P.leafOffset(), P.leafSize(), a, b, y); + // When we are inserting at the end of a leaf node, we must update stops. + unsigned Size = P.leafSize(); + bool Grow = P.leafOffset() == Size; + Size = P.leaf().insertFrom(P.leafOffset(), Size, 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"); + if (Size > Leaf::Capacity) { + overflow(P.height()); + Grow = P.leafOffset() == P.leafSize(); + Size = P.leaf().insertFrom(P.leafOffset(), P.leafSize(), a, b, y); + assert(Size <= Leaf::Capacity && "overflow() didn't make room"); } // Inserted, update offset and leaf size. - P.leafOffset() = IP.first; - P.setSize(IM.height, IP.second); + P.setSize(P.height(), Size); // Insert was the last node entry, update stops. - if (IP.first == IP.second - 1) - setNodeStop(IM.height, P.leaf().stop(IP.first)); + if (Grow) + setNodeStop(P.height(), b); } /// erase - erase the current interval and move to the next position. diff --git a/unittests/ADT/IntervalMapTest.cpp b/unittests/ADT/IntervalMapTest.cpp index 6b8e761ae70..445afcaf7a2 100644 --- a/unittests/ADT/IntervalMapTest.cpp +++ b/unittests/ADT/IntervalMapTest.cpp @@ -116,50 +116,26 @@ TEST(IntervalMapTest, RootCoalescing) { EXPECT_EQ(90u, map.start()); EXPECT_EQ(150u, map.stop()); - // Overlap left. - map.insert(80, 100, 1); - EXPECT_EQ(1, std::distance(map.begin(), map.end())); - EXPECT_EQ(80u, map.start()); - EXPECT_EQ(150u, map.stop()); - - // Inside. - map.insert(100, 130, 1); - EXPECT_EQ(1, std::distance(map.begin(), map.end())); - EXPECT_EQ(80u, map.start()); - EXPECT_EQ(150u, map.stop()); - - // Overlap both. - map.insert(70, 160, 1); - EXPECT_EQ(1, std::distance(map.begin(), map.end())); - EXPECT_EQ(70u, map.start()); - EXPECT_EQ(160u, map.stop()); - - // Overlap right. - map.insert(80, 170, 1); - EXPECT_EQ(1, std::distance(map.begin(), map.end())); - EXPECT_EQ(70u, map.start()); - EXPECT_EQ(170u, map.stop()); - // Coalesce from the right. - map.insert(170, 200, 1); + map.insert(151, 200, 1); EXPECT_EQ(1, std::distance(map.begin(), map.end())); - EXPECT_EQ(70u, map.start()); + EXPECT_EQ(90u, map.start()); EXPECT_EQ(200u, map.stop()); // Non-coalesce from the left. - map.insert(60, 69, 2); + map.insert(60, 89, 2); EXPECT_EQ(2, std::distance(map.begin(), map.end())); EXPECT_EQ(60u, map.start()); EXPECT_EQ(200u, map.stop()); - EXPECT_EQ(2u, map.lookup(69)); - EXPECT_EQ(1u, map.lookup(70)); + EXPECT_EQ(2u, map.lookup(89)); + EXPECT_EQ(1u, map.lookup(90)); UUMap::iterator I = map.begin(); EXPECT_EQ(60u, I.start()); - EXPECT_EQ(69u, I.stop()); + EXPECT_EQ(89u, I.stop()); EXPECT_EQ(2u, I.value()); ++I; - EXPECT_EQ(70u, I.start()); + EXPECT_EQ(90u, I.start()); EXPECT_EQ(200u, I.stop()); EXPECT_EQ(1u, I.value()); ++I; @@ -176,13 +152,13 @@ TEST(IntervalMapTest, RootCoalescing) { // Erase from the left. map.begin().erase(); EXPECT_EQ(2, std::distance(map.begin(), map.end())); - EXPECT_EQ(70u, map.start()); + EXPECT_EQ(90u, map.start()); EXPECT_EQ(210u, map.stop()); // Erase from the right. (--map.end()).erase(); EXPECT_EQ(1, std::distance(map.begin(), map.end())); - EXPECT_EQ(70u, map.start()); + EXPECT_EQ(90u, map.start()); EXPECT_EQ(200u, map.stop()); } @@ -288,70 +264,6 @@ TEST(IntervalMapTest, RootMultiCoalescing) { ++I; EXPECT_FALSE(I.valid()); - // Coalesce multiple with overlap right. - // [100;115] [120;150] [160;170] - map.insert(116, 165, 1); - I = map.begin(); - ASSERT_TRUE(I.valid()); - EXPECT_EQ(100u, I.start()); - EXPECT_EQ(170u, I.stop()); - ++I; - EXPECT_FALSE(I.valid()); - - // Coalesce multiple with overlap left - // [100;170] - map.insert(180, 190, 1); - map.insert(200, 210, 1); - map.insert(220, 230, 1); - // [100;170] [180;190] [200;210] [220;230] - map.insert(160, 199, 1); - I = map.begin(); - ASSERT_TRUE(I.valid()); - EXPECT_EQ(100u, I.start()); - EXPECT_EQ(210u, I.stop()); - ++I; - ASSERT_TRUE(I.valid()); - EXPECT_EQ(220u, I.start()); - EXPECT_EQ(230u, I.stop()); - ++I; - EXPECT_FALSE(I.valid()); - - // Overwrite 2 from gap to gap. - // [100;210] [220;230] - map.insert(50, 250, 1); - I = map.begin(); - ASSERT_TRUE(I.valid()); - EXPECT_EQ(50u, I.start()); - EXPECT_EQ(250u, I.stop()); - ++I; - EXPECT_FALSE(I.valid()); - - // Coalesce at end of full root. - // [50;250] - map.insert(260, 270, 1); - map.insert(280, 290, 1); - map.insert(300, 310, 1); - // [50;250] [260;270] [280;290] [300;310] - map.insert(311, 320, 1); - I = map.begin(); - ASSERT_TRUE(I.valid()); - EXPECT_EQ(50u, I.start()); - EXPECT_EQ(250u, I.stop()); - ++I; - ASSERT_TRUE(I.valid()); - EXPECT_EQ(260u, I.start()); - EXPECT_EQ(270u, I.stop()); - ++I; - ASSERT_TRUE(I.valid()); - EXPECT_EQ(280u, I.start()); - EXPECT_EQ(290u, I.stop()); - ++I; - ASSERT_TRUE(I.valid()); - EXPECT_EQ(300u, I.start()); - EXPECT_EQ(320u, I.stop()); - ++I; - EXPECT_FALSE(I.valid()); - // Test clear() on non-branched map. map.clear(); EXPECT_TRUE(map.empty());