Skip to content

Commit

Permalink
Add support for DenseMap/DenseSet count and find using const pointers
Browse files Browse the repository at this point in the history
Summary:
Similar to SmallPtrSet, this makes find and count work with both const
referneces and const pointers.

Reviewers: dblaikie

Subscribers: llvm-commits, mzolotukhin

Differential Revision: https://reviews.llvm.org/D30713

llvm-svn: 297424
  • Loading branch information
dberlin committed Mar 10, 2017
1 parent e42462d commit 04d9e74
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 10 deletions.
11 changes: 7 additions & 4 deletions llvm/include/llvm/ADT/DenseMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class DenseMapIterator;
template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
typename BucketT>
class DenseMapBase : public DebugEpochBase {
template <typename T>
using const_arg_type_t = typename const_pointer_or_const_ref<T>::type;

public:
typedef unsigned size_type;
typedef KeyT key_type;
Expand Down Expand Up @@ -119,18 +122,18 @@ class DenseMapBase : public DebugEpochBase {
}

/// Return 1 if the specified key is in the map, 0 otherwise.
size_type count(const KeyT &Val) const {
size_type count(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
return LookupBucketFor(Val, TheBucket) ? 1 : 0;
}

iterator find(const KeyT &Val) {
iterator find(const_arg_type_t<KeyT> Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return iterator(TheBucket, getBucketsEnd(), *this, true);
return end();
}
const_iterator find(const KeyT &Val) const {
const_iterator find(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return const_iterator(TheBucket, getBucketsEnd(), *this, true);
Expand Down Expand Up @@ -159,7 +162,7 @@ class DenseMapBase : public DebugEpochBase {

/// lookup - Return the entry for the specified key, or a default
/// constructed value if no such entry exists.
ValueT lookup(const KeyT &Val) const {
ValueT lookup(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return TheBucket->getSecond();
Expand Down
8 changes: 5 additions & 3 deletions llvm/include/llvm/ADT/DenseSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class DenseSetImpl {
static_assert(sizeof(typename MapTy::value_type) == sizeof(ValueT),
"DenseMap buckets unexpectedly large!");
MapTy TheMap;
template <typename T>
using const_arg_type_t = typename const_pointer_or_const_ref<T>::type;

public:
typedef ValueT key_type;
Expand Down Expand Up @@ -78,7 +80,7 @@ class DenseSetImpl {
}

/// Return 1 if the specified key is in the set, 0 otherwise.
size_type count(const ValueT &V) const {
size_type count(const_arg_type_t<ValueT> V) const {
return TheMap.count(V);
}

Expand Down Expand Up @@ -154,8 +156,8 @@ class DenseSetImpl {
const_iterator begin() const { return ConstIterator(TheMap.begin()); }
const_iterator end() const { return ConstIterator(TheMap.end()); }

iterator find(const ValueT &V) { return Iterator(TheMap.find(V)); }
const_iterator find(const ValueT &V) const {
iterator find(const_arg_type_t<ValueT> V) { return Iterator(TheMap.find(V)); }
const_iterator find(const_arg_type_t<ValueT> V) const {
return ConstIterator(TheMap.find(V));
}

Expand Down
9 changes: 9 additions & 0 deletions llvm/include/llvm/Support/type_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ struct add_const_past_pointer<
typedef const typename std::remove_pointer<T>::type *type;
};

template <typename T, typename Enable = void>
struct const_pointer_or_const_ref {
using type = const T &;
};
template <typename T>
struct const_pointer_or_const_ref<
T, typename std::enable_if<std::is_pointer<T>::value>::type> {
using type = typename add_const_past_pointer<T>::type;
};
}

// If the compiler supports detecting whether a class is final, define
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3657,7 +3657,7 @@ void InnerLoopVectorizer::fixupIVUsers(PHINode *OrigPhi,

namespace {
struct CSEDenseMapInfo {
static bool canHandle(Instruction *I) {
static bool canHandle(const Instruction *I) {
return isa<InsertElementInst>(I) || isa<ExtractElementInst>(I) ||
isa<ShuffleVectorInst>(I) || isa<GetElementPtrInst>(I);
}
Expand All @@ -3667,12 +3667,12 @@ struct CSEDenseMapInfo {
static inline Instruction *getTombstoneKey() {
return DenseMapInfo<Instruction *>::getTombstoneKey();
}
static unsigned getHashValue(Instruction *I) {
static unsigned getHashValue(const Instruction *I) {
assert(canHandle(I) && "Unknown instruction!");
return hash_combine(I->getOpcode(), hash_combine_range(I->value_op_begin(),
I->value_op_end()));
}
static bool isEqual(Instruction *LHS, Instruction *RHS) {
static bool isEqual(const Instruction *LHS, const Instruction *RHS) {
if (LHS == getEmptyKey() || RHS == getEmptyKey() ||
LHS == getTombstoneKey() || RHS == getTombstoneKey())
return LHS == RHS;
Expand Down
14 changes: 14 additions & 0 deletions llvm/unittests/ADT/DenseMapTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,4 +580,18 @@ TEST(DenseMapCustomTest, TryEmplaceTest) {
EXPECT_EQ(Try1.first, Try2.first);
EXPECT_NE(nullptr, P);
}

TEST(DenseMapCustomTest, ConstTest) {
// Test that const pointers work okay for count and find, even when the
// underlying map is a non-const pointer.
DenseMap<int *, int> Map;
int A;
int *B = &A;
const int *C = &A;
Map.insert({B, 0});
EXPECT_EQ(Map.count(B), 1u);
EXPECT_EQ(Map.count(C), 1u);
EXPECT_NE(Map.find(B), Map.end());
EXPECT_NE(Map.find(C), Map.end());
}
}
13 changes: 13 additions & 0 deletions llvm/unittests/ADT/DenseSetTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,17 @@ TEST(DenseSetCustomTest, ReserveTest) {
EXPECT_EQ(0, CountCopyAndMove::Copy);
}
}
TEST(DenseSetCustomTest, ConstTest) {
// Test that const pointers work okay for count and find, even when the
// underlying map is a non-const pointer.
DenseSet<int *> Map;
int A;
int *B = &A;
const int *C = &A;
Map.insert(B);
EXPECT_EQ(Map.count(B), 1u);
EXPECT_EQ(Map.count(C), 1u);
EXPECT_NE(Map.find(B), Map.end());
EXPECT_NE(Map.find(C), Map.end());
}
}

0 comments on commit 04d9e74

Please sign in to comment.