Skip to content

Commit

Permalink
[ADT] Add at method (assertive lookup) to DenseMap and StringMap
Browse files Browse the repository at this point in the history
This patch makes it easier for users when they want to use validated
lookup on DenseMap/StringMap as a composable C++ expression. For
instance:

```
// instead of
if (auto val = map.lookup(key))
   return val;
assert("...");

// we can write
return map.at(key);
```

Differential Revision: https://reviews.llvm.org/D143976
  • Loading branch information
StrongerXi committed Feb 17, 2023
1 parent 2b51c8c commit 1320036
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 3 deletions.
8 changes: 8 additions & 0 deletions llvm/include/llvm/ADT/DenseMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,14 @@ class DenseMapBase : public DebugEpochBase {
return ValueT();
}

/// at - Return the entry for the specified key, or abort if no such
/// entry exists.
const ValueT &at(const_arg_type_t<KeyT> Val) const {
auto Iter = this->find(std::move(Val));
assert(Iter != this->end() && "DenseMap::at failed due to a missing key");
return Iter->second;
}

// Inserts key,value pair into the map if the key isn't already in the map.
// If the key is already in the map, it returns false and doesn't update the
// value.
Expand Down
14 changes: 11 additions & 3 deletions llvm/include/llvm/ADT/StringMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,20 @@ class StringMap : public StringMapImpl,
/// lookup - Return the entry for the specified key, or a default
/// constructed value if no such entry exists.
ValueTy lookup(StringRef Key) const {
const_iterator it = find(Key);
if (it != end())
return it->second;
const_iterator Iter = find(Key);
if (Iter != end())
return Iter->second;
return ValueTy();
}

/// at - Return the entry for the specified key, or abort if no such
/// entry exists.
const ValueTy &at(StringRef Val) const {
auto Iter = this->find(std::move(Val));
assert(Iter != this->end() && "StringMap::at failed due to a missing key");
return Iter->second;
}

/// Lookup the ValueTy for the \p Key, or create a default constructed value
/// if the key is not in the map.
ValueTy &operator[](StringRef Key) { return try_emplace(Key).first->second; }
Expand Down
8 changes: 8 additions & 0 deletions llvm/unittests/ADT/DenseMapTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ TYPED_TEST(DenseMapTest, EmptyIntMapTest) {
EXPECT_TRUE(this->Map.find(this->getKey()) == this->Map.end());
EXPECT_EQ(typename TypeParam::mapped_type(),
this->Map.lookup(this->getKey()));

// LookupOrTrap tests
EXPECT_DEATH({ this->Map.at(this->getKey()); },
"DenseMap::at failed due to a missing key");
}

// Constant map tests
Expand Down Expand Up @@ -156,6 +160,10 @@ TYPED_TEST(DenseMapTest, SingleEntryMapTest) {
EXPECT_TRUE(this->Map.find(this->getKey()) == this->Map.begin());
EXPECT_EQ(this->getValue(), this->Map.lookup(this->getKey()));
EXPECT_EQ(this->getValue(), this->Map[this->getKey()]);

// LookupOrTrap tests
EXPECT_DEATH({ this->Map.at(this->getKey(1)); },
"DenseMap::at failed due to a missing key");
}

// Test clear() method
Expand Down
16 changes: 16 additions & 0 deletions llvm/unittests/ADT/StringMapTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,22 @@ TEST_F(StringMapTest, CopyCtorTest) {
EXPECT_EQ(5, Map2.lookup("funf"));
}

TEST_F(StringMapTest, LookupOrTrapTest) {
llvm::StringMap<int> Map;

// key not found on empty map
EXPECT_DEATH({ Map.at("a"); }, "StringMap::at failed due to a missing key");

// keys both found and not found on non-empty map
Map["a"] = 1;
Map["b"] = 2;
Map["c"] = 3;
EXPECT_EQ(1, Map.at("a"));
EXPECT_EQ(2, Map.at("b"));
EXPECT_EQ(3, Map.at("c"));
EXPECT_DEATH({ Map.at("d"); }, "StringMap::at failed due to a missing key");
}

// A more complex iteration test.
TEST_F(StringMapTest, IterationTest) {
bool visited[100];
Expand Down

0 comments on commit 1320036

Please sign in to comment.