[frozen-multimap] Add support for erasing once we have finished constructing the map.

I implemented this in a similar way to the way blotting is implemented in a blot
map vector:

1. I changed this to store (Key, Optional<Value>) pairs.

2. I made it so that once frozen, we can "erase" things from the multimap by
setting all Optional<Value> to none.

3. I changed the range we vend to be an OptionalTransformRange instead of just a
TransformRange so we skip all keys with .none values, meaning that a user will
get the nice behavior that getRange() still works after erasing.

One interesting thing to note is that one /cannot/ erase elements when
initializing the frozen multi-map since we haven't sorted it yet. At first this
seems weird, but it actually fits with the use case of this data structure:
building up state by processing IR in a readonly way and then later working with
it in a worklist like way (and perhaps checking for unhandled cases at the end
of processing).

The nice thing additional thing is that I was able to ensure that the actual
exposed API did not change in terms of how one uses it. I just changed the
underlying iterators/etc.
This commit is contained in:
Michael Gottesman
2020-04-28 13:11:03 -07:00
parent 07738e55a9
commit 9568d53c8f
2 changed files with 212 additions and 38 deletions

View File

@@ -223,3 +223,101 @@ TEST(FrozenMultiMapCustomTest, RandomAgainstStdMultiMap) {
}
}
}
TEST(FrozenMultiMapCustomTest, SimpleErase1) {
Canary::resetIDs();
FrozenMultiMap<Canary, Canary> map;
auto key1 = Canary();
auto key2 = Canary();
map.insert(key1, Canary());
map.insert(key1, Canary());
map.insert(key1, Canary());
map.insert(key2, Canary());
map.insert(key2, Canary());
map.setFrozen();
EXPECT_EQ(map.size(), 5u);
EXPECT_TRUE(map.erase(key2));
EXPECT_FALSE(map.erase(key2));
{
auto range = map.getRange();
EXPECT_EQ(std::distance(range.begin(), range.end()), 1);
{
auto begin = range.begin();
auto end = range.end();
++begin;
EXPECT_EQ(std::distance(begin, end), 0);
}
auto iter = range.begin();
{
auto p = *iter;
EXPECT_EQ(p.first.getID(), key1.getID());
EXPECT_EQ(p.second.size(), 3u);
EXPECT_EQ(p.second[0].getID(), 2u);
EXPECT_EQ(p.second[1].getID(), 3u);
EXPECT_EQ(p.second[2].getID(), 4u);
}
}
EXPECT_TRUE(map.erase(key1));
EXPECT_FALSE(map.erase(key1));
{
auto range = map.getRange();
EXPECT_EQ(std::distance(range.begin(), range.end()), 0);
}
}
TEST(FrozenMultiMapCustomTest, SimpleErase2) {
Canary::resetIDs();
FrozenMultiMap<Canary, Canary> map;
auto key1 = Canary();
auto key2 = Canary();
map.insert(key1, Canary());
map.insert(key1, Canary());
map.insert(key1, Canary());
map.insert(key2, Canary());
map.insert(key2, Canary());
map.setFrozen();
EXPECT_EQ(map.size(), 5u);
EXPECT_TRUE(map.erase(key1));
{
auto range = map.getRange();
EXPECT_EQ(std::distance(range.begin(), range.end()), 1);
{
auto begin = range.begin();
auto end = range.end();
++begin;
EXPECT_EQ(std::distance(begin, end), 0);
}
auto iter = range.begin();
{
auto p = *iter;
EXPECT_EQ(p.first.getID(), key2.getID());
EXPECT_EQ(p.second.size(), 2u);
EXPECT_EQ(p.second[0].getID(), 5u);
EXPECT_EQ(p.second[1].getID(), 6u);
}
}
EXPECT_TRUE(map.erase(key2));
EXPECT_FALSE(map.erase(key2));
{
auto range = map.getRange();
EXPECT_EQ(std::distance(range.begin(), range.end()), 0);
}
}