From 9ece8eb9456421244dbf894676848574f21b401f Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Wed, 24 Jun 2015 10:06:29 +0000 Subject: [PATCH] [ADT] Teach DenseMap to support StringRef keys. While often you want to use something specialized like StringMap, when the strings already have persistent storage a normal densemap over them can be more efficient. This can't go into StringRef.h because of really obnoxious header chains from the hashing code to the endian detection code to CPU feature detection code to StringMap. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@240528 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ADT/DenseMapInfo.h | 27 +++++++++++++++++++++++++++ unittests/ADT/DenseMapTest.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/include/llvm/ADT/DenseMapInfo.h b/include/llvm/ADT/DenseMapInfo.h index 6f17a647b63..b0a05307207 100644 --- a/include/llvm/ADT/DenseMapInfo.h +++ b/include/llvm/ADT/DenseMapInfo.h @@ -14,6 +14,8 @@ #ifndef LLVM_ADT_DENSEMAPINFO_H #define LLVM_ADT_DENSEMAPINFO_H +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include "llvm/Support/type_traits.h" @@ -163,6 +165,31 @@ struct DenseMapInfo > { } }; +// Provide DenseMapInfo for StringRefs. +template <> struct DenseMapInfo { + static inline StringRef getEmptyKey() { + return StringRef(reinterpret_cast(~static_cast(0)), + 0); + } + static inline StringRef getTombstoneKey() { + return StringRef(reinterpret_cast(~static_cast(1)), + 0); + } + static unsigned getHashValue(StringRef Val) { + assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!"); + assert(Val.data() != getTombstoneKey().data() && + "Cannot hash the tombstone key!"); + return (unsigned)(hash_value(Val)); + } + static bool isEqual(StringRef LHS, StringRef RHS) { + if (RHS.data() == getEmptyKey().data()) + return LHS.data() == getEmptyKey().data(); + if (RHS.data() == getTombstoneKey().data()) + return LHS.data() == getTombstoneKey().data(); + return LHS == RHS; + } +}; + } // end namespace llvm #endif diff --git a/unittests/ADT/DenseMapTest.cpp b/unittests/ADT/DenseMapTest.cpp index 97807771725..2c6fe358832 100644 --- a/unittests/ADT/DenseMapTest.cpp +++ b/unittests/ADT/DenseMapTest.cpp @@ -323,6 +323,31 @@ TYPED_TEST(DenseMapTest, ConstIteratorTest) { EXPECT_TRUE(cit == cit2); } +// Make sure DenseMap works with StringRef keys. +TEST(DenseMapCustomTest, StringRefTest) { + DenseMap M; + + M["a"] = 1; + M["b"] = 2; + M["c"] = 3; + + EXPECT_EQ(3u, M.size()); + EXPECT_EQ(1, M.lookup("a")); + EXPECT_EQ(2, M.lookup("b")); + EXPECT_EQ(3, M.lookup("c")); + + EXPECT_EQ(0, M.lookup("q")); + + // Test the empty string, spelled various ways. + EXPECT_EQ(0, M.lookup("")); + EXPECT_EQ(0, M.lookup(StringRef())); + EXPECT_EQ(0, M.lookup(StringRef("a", 0))); + M[""] = 42; + EXPECT_EQ(42, M.lookup("")); + EXPECT_EQ(42, M.lookup(StringRef())); + EXPECT_EQ(42, M.lookup(StringRef("a", 0))); +} + // Key traits that allows lookup with either an unsigned or char* key; // In the latter case, "a" == 0, "b" == 1 and so on. struct TestDenseMapInfo {