Disallow overlapping inserts, even when inserting the same value.

We always disallowed overlapping inserts with different values, and this makes
the insertion code smaller and faster.

If an overwriting insert is needed, it can be added as a separate method that
trims any existing intervals before inserting. The immediate use cases for
IntervalMap don't need this - they only use disjoint insertions.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120264 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jakob Stoklund Olesen 2010-11-28 22:17:11 +00:00
parent d652dbe720
commit 5f456cda98
2 changed files with 54 additions and 174 deletions

View File

@ -586,8 +586,7 @@ public:
return Traits::startLess(x, start(i)) ? NotFound : value(i); return Traits::startLess(x, start(i)) ? NotFound : value(i);
} }
IdxPair insertFrom(unsigned i, unsigned Size, KeyT a, KeyT b, ValT y); unsigned insertFrom(unsigned &Pos, unsigned Size, KeyT a, KeyT b, ValT y);
unsigned extendStop(unsigned i, unsigned Size, KeyT b);
#ifndef NDEBUG #ifndef NDEBUG
void dump(raw_ostream &OS, unsigned Size) { void dump(raw_ostream &OS, unsigned Size) {
@ -610,91 +609,58 @@ public:
/// @param y Value be mapped. /// @param y Value be mapped.
/// @return (insert position, new size), or (i, Capacity+1) on overflow. /// @return (insert position, new size), or (i, Capacity+1) on overflow.
template <typename KeyT, typename ValT, unsigned N, typename Traits> template <typename KeyT, typename ValT, unsigned N, typename Traits>
IdxPair LeafNode<KeyT, ValT, N, Traits>:: unsigned LeafNode<KeyT, ValT, N, Traits>::
insertFrom(unsigned i, unsigned Size, KeyT a, KeyT b, ValT y) { insertFrom(unsigned &Pos, unsigned Size, KeyT a, KeyT b, ValT y) {
unsigned i = Pos;
assert(i <= Size && Size <= N && "Invalid index"); assert(i <= Size && Size <= N && "Invalid index");
assert(!Traits::stopLess(b, a) && "Invalid interval"); assert(!Traits::stopLess(b, a) && "Invalid interval");
// Verify the findFrom invariant. // Verify the findFrom invariant.
assert((i == 0 || Traits::stopLess(stop(i - 1), a))); assert((i == 0 || Traits::stopLess(stop(i - 1), a)));
assert((i == Size || !Traits::stopLess(stop(i), a))); assert((i == Size || !Traits::stopLess(stop(i), a)));
assert((i == Size || Traits::stopLess(b, start(i))) && "Overlapping insert");
// Coalesce with previous interval. // Coalesce with previous interval.
if (i && value(i - 1) == y && Traits::adjacent(stop(i - 1), a)) if (i && value(i - 1) == y && Traits::adjacent(stop(i - 1), a)) {
return IdxPair(i - 1, extendStop(i - 1, Size, b)); 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. // Detect overflow.
if (i == N) if (i == N)
return IdxPair(i, N + 1); return N + 1;
// Add new interval at end. // Add new interval at end.
if (i == Size) { if (i == Size) {
start(i) = a; start(i) = a;
stop(i) = b; stop(i) = b;
value(i) = y; value(i) = y;
return IdxPair(i, Size + 1); return 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));
} }
// Try to coalesce with following interval. // Try to coalesce with following interval.
if (value(i) == y && Traits::adjacent(b, start(i))) { if (value(i) == y && Traits::adjacent(b, start(i))) {
start(i) = a; start(i) = a;
return IdxPair(i, Size); return Size;
} }
// We must insert before i. Detect overflow. // We must insert before i. Detect overflow.
if (Size == N) if (Size == N)
return IdxPair(i, N + 1); return N + 1;
// Insert before i. // Insert before i.
this->shift(i, Size); this->shift(i, Size);
start(i) = a; start(i) = a;
stop(i) = b; stop(i) = b;
value(i) = y; value(i) = y;
return IdxPair(i, Size + 1); return 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 <typename KeyT, typename ValT, unsigned N, typename Traits>
unsigned LeafNode<KeyT, ValT, N, Traits>::
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));
} }
@ -1138,7 +1104,7 @@ public:
// Easy insert into root leaf. // Easy insert into root leaf.
unsigned p = rootLeaf().findFrom(0, rootSize, a); 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. /// clear - Remove all entries.
@ -1697,12 +1663,11 @@ iterator::insert(KeyT a, KeyT b, ValT y) {
IntervalMapImpl::Path &P = this->path; IntervalMapImpl::Path &P = this->path;
// Try simple root leaf insert. // 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? // Was the root node insert successful?
if (IP.second <= RootLeaf::Capacity) { if (Size <= RootLeaf::Capacity) {
P.leafOffset() = IP.first; P.setSize(0, IM.rootSize = Size);
P.setSize(0, IM.rootSize = IP.second);
return; return;
} }
@ -1719,14 +1684,15 @@ template <typename KeyT, typename ValT, unsigned N, typename Traits>
void IntervalMap<KeyT, ValT, N, Traits>:: void IntervalMap<KeyT, ValT, N, Traits>::
iterator::treeInsert(KeyT a, KeyT b, ValT y) { iterator::treeInsert(KeyT a, KeyT b, ValT y) {
using namespace IntervalMapImpl; using namespace IntervalMapImpl;
IntervalMap &IM = *this->map;
Path &P = this->path; Path &P = this->path;
if (!P.valid())
P.legalizeForInsert(this->map->height);
// Check if this insertion will extend the node to the left. // Check if this insertion will extend the node to the left.
if (P.valid() && P.leafOffset() == 0 && if (P.leafOffset() == 0 && Traits::startLess(a, P.leaf<Leaf>().start(0))) {
Traits::startLess(a, P.leaf<Leaf>().start(0))) {
// Node is growing to the left, will it affect a left sibling node? // 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<Leaf>(); Leaf &SibLeaf = Sib.get<Leaf>();
unsigned SibOfs = Sib.size() - 1; unsigned SibOfs = Sib.size() - 1;
if (SibLeaf.value(SibOfs) == y && 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. // 2. Extend a to SibLeaf, erase the SibLeaf entry and continue.
// We prefer 1., but need 2 when coalescing to the right as well. // We prefer 1., but need 2 when coalescing to the right as well.
Leaf &CurLeaf = P.leaf<Leaf>(); Leaf &CurLeaf = P.leaf<Leaf>();
P.moveLeft(IM.height); P.moveLeft(P.height());
if (Traits::stopLess(b, CurLeaf.start(0)) && if (Traits::stopLess(b, CurLeaf.start(0)) &&
(y != CurLeaf.value(0) || !Traits::adjacent(b, CurLeaf.start(0)))) { (y != CurLeaf.value(0) || !Traits::adjacent(b, CurLeaf.start(0)))) {
// Easy, just extend SibLeaf and we're done. // Easy, just extend SibLeaf and we're done.
setNodeStop(IM.height, SibLeaf.stop(SibOfs) = b); setNodeStop(P.height(), SibLeaf.stop(SibOfs) = b);
return; return;
} else { } else {
// We have both left and right coalescing. Erase the old SibLeaf entry // 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 { } else {
// No left sibling means we are at begin(). Update cached bound. // No left sibling means we are at begin(). Update cached bound.
IM.rootBranchStart() = a; this->map->rootBranchStart() = a;
} }
} }
P.legalizeForInsert(IM.height); // When we are inserting at the end of a leaf node, we must update stops.
IdxPair IP = P.leaf<Leaf>().insertFrom(P.leafOffset(), P.leafSize(), a, b, y); unsigned Size = P.leafSize();
bool Grow = P.leafOffset() == Size;
Size = P.leaf<Leaf>().insertFrom(P.leafOffset(), Size, a, b, y);
// Leaf insertion unsuccessful? Overflow and try again. // Leaf insertion unsuccessful? Overflow and try again.
if (IP.second > Leaf::Capacity) { if (Size > Leaf::Capacity) {
overflow<Leaf>(IM.height); overflow<Leaf>(P.height());
IP = P.leaf<Leaf>().insertFrom(P.leafOffset(), P.leafSize(), a, b, y); Grow = P.leafOffset() == P.leafSize();
assert(IP.second <= Leaf::Capacity && "overflow() didn't make room"); Size = P.leaf<Leaf>().insertFrom(P.leafOffset(), P.leafSize(), a, b, y);
assert(Size <= Leaf::Capacity && "overflow() didn't make room");
} }
// Inserted, update offset and leaf size. // Inserted, update offset and leaf size.
P.leafOffset() = IP.first; P.setSize(P.height(), Size);
P.setSize(IM.height, IP.second);
// Insert was the last node entry, update stops. // Insert was the last node entry, update stops.
if (IP.first == IP.second - 1) if (Grow)
setNodeStop(IM.height, P.leaf<Leaf>().stop(IP.first)); setNodeStop(P.height(), b);
} }
/// erase - erase the current interval and move to the next position. /// erase - erase the current interval and move to the next position.

View File

@ -116,50 +116,26 @@ TEST(IntervalMapTest, RootCoalescing) {
EXPECT_EQ(90u, map.start()); EXPECT_EQ(90u, map.start());
EXPECT_EQ(150u, map.stop()); 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. // 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(1, std::distance(map.begin(), map.end()));
EXPECT_EQ(70u, map.start()); EXPECT_EQ(90u, map.start());
EXPECT_EQ(200u, map.stop()); EXPECT_EQ(200u, map.stop());
// Non-coalesce from the left. // 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(2, std::distance(map.begin(), map.end()));
EXPECT_EQ(60u, map.start()); EXPECT_EQ(60u, map.start());
EXPECT_EQ(200u, map.stop()); EXPECT_EQ(200u, map.stop());
EXPECT_EQ(2u, map.lookup(69)); EXPECT_EQ(2u, map.lookup(89));
EXPECT_EQ(1u, map.lookup(70)); EXPECT_EQ(1u, map.lookup(90));
UUMap::iterator I = map.begin(); UUMap::iterator I = map.begin();
EXPECT_EQ(60u, I.start()); EXPECT_EQ(60u, I.start());
EXPECT_EQ(69u, I.stop()); EXPECT_EQ(89u, I.stop());
EXPECT_EQ(2u, I.value()); EXPECT_EQ(2u, I.value());
++I; ++I;
EXPECT_EQ(70u, I.start()); EXPECT_EQ(90u, I.start());
EXPECT_EQ(200u, I.stop()); EXPECT_EQ(200u, I.stop());
EXPECT_EQ(1u, I.value()); EXPECT_EQ(1u, I.value());
++I; ++I;
@ -176,13 +152,13 @@ TEST(IntervalMapTest, RootCoalescing) {
// Erase from the left. // Erase from the left.
map.begin().erase(); map.begin().erase();
EXPECT_EQ(2, std::distance(map.begin(), map.end())); EXPECT_EQ(2, std::distance(map.begin(), map.end()));
EXPECT_EQ(70u, map.start()); EXPECT_EQ(90u, map.start());
EXPECT_EQ(210u, map.stop()); EXPECT_EQ(210u, map.stop());
// Erase from the right. // Erase from the right.
(--map.end()).erase(); (--map.end()).erase();
EXPECT_EQ(1, std::distance(map.begin(), map.end())); EXPECT_EQ(1, std::distance(map.begin(), map.end()));
EXPECT_EQ(70u, map.start()); EXPECT_EQ(90u, map.start());
EXPECT_EQ(200u, map.stop()); EXPECT_EQ(200u, map.stop());
} }
@ -288,70 +264,6 @@ TEST(IntervalMapTest, RootMultiCoalescing) {
++I; ++I;
EXPECT_FALSE(I.valid()); 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. // Test clear() on non-branched map.
map.clear(); map.clear();
EXPECT_TRUE(map.empty()); EXPECT_TRUE(map.empty());