Skip to content

Commit d110c3a

Browse files
committed
[ADT] Support BitVector as a key in DenseSet/Map
This patch adds DenseMapInfo<> support for BitVector and SmallBitVector. This is part of https://reviews.llvm.org/D71775, where a BitVector is used as a thread affinity mask.
1 parent c293107 commit d110c3a

File tree

3 files changed

+96
-0
lines changed

3 files changed

+96
-0
lines changed

llvm/include/llvm/ADT/BitVector.h

+34
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define LLVM_ADT_BITVECTOR_H
1515

1616
#include "llvm/ADT/ArrayRef.h"
17+
#include "llvm/ADT/DenseMapInfo.h"
1718
#include "llvm/ADT/iterator_range.h"
1819
#include "llvm/Support/MathExtras.h"
1920
#include <algorithm>
@@ -719,6 +720,14 @@ class BitVector {
719720
if (this == &RHS) return *this;
720721

721722
Size = RHS.size();
723+
724+
// Handle tombstone when the BitVector is a key of a DenseHash.
725+
if (RHS.isInvalid()) {
726+
std::free(Bits.data());
727+
Bits = None;
728+
return *this;
729+
}
730+
722731
unsigned RHSWords = NumBitWords(Size);
723732
if (Size <= getBitCapacity()) {
724733
if (Size)
@@ -758,6 +767,14 @@ class BitVector {
758767
std::swap(Size, RHS.Size);
759768
}
760769

770+
void invalid() {
771+
assert(!Size && Bits.empty());
772+
Size = (unsigned)-1;
773+
}
774+
bool isInvalid() const { return Size == (unsigned)-1; }
775+
776+
ArrayRef<BitWord> getData() const { return Bits; }
777+
761778
//===--------------------------------------------------------------------===//
762779
// Portable bit mask operations.
763780
//===--------------------------------------------------------------------===//
@@ -932,6 +949,23 @@ inline size_t capacity_in_bytes(const BitVector &X) {
932949
return X.getMemorySize();
933950
}
934951

952+
template <> struct DenseMapInfo<BitVector> {
953+
static inline BitVector getEmptyKey() { return BitVector(); }
954+
static inline BitVector getTombstoneKey() {
955+
BitVector V;
956+
V.invalid();
957+
return V;
958+
}
959+
static unsigned getHashValue(const BitVector &V) {
960+
return DenseMapInfo<std::pair<unsigned, ArrayRef<uintptr_t>>>::getHashValue(
961+
std::make_pair(V.size(), V.getData()));
962+
}
963+
static bool isEqual(const BitVector &LHS, const BitVector &RHS) {
964+
if (LHS.isInvalid() || RHS.isInvalid())
965+
return LHS.isInvalid() == RHS.isInvalid();
966+
return LHS == RHS;
967+
}
968+
};
935969
} // end namespace llvm
936970

937971
namespace std {

llvm/include/llvm/ADT/SmallBitVector.h

+27
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,16 @@ class SmallBitVector {
662662
getPointer()->clearBitsNotInMask(Mask, MaskWords);
663663
}
664664

665+
void invalid() {
666+
assert(empty());
667+
X = (uintptr_t)-1;
668+
}
669+
bool isInvalid() const { return X == (uintptr_t)-1; }
670+
671+
ArrayRef<uintptr_t> getData() const {
672+
return isSmall() ? makeArrayRef(X) : getPointer()->getData();
673+
}
674+
665675
private:
666676
template <bool AddBits, bool InvertMask>
667677
void applyMask(const uint32_t *Mask, unsigned MaskWords) {
@@ -699,6 +709,23 @@ operator^(const SmallBitVector &LHS, const SmallBitVector &RHS) {
699709
return Result;
700710
}
701711

712+
template <> struct DenseMapInfo<SmallBitVector> {
713+
static inline SmallBitVector getEmptyKey() { return SmallBitVector(); }
714+
static inline SmallBitVector getTombstoneKey() {
715+
SmallBitVector V;
716+
V.invalid();
717+
return V;
718+
}
719+
static unsigned getHashValue(const SmallBitVector &V) {
720+
return DenseMapInfo<std::pair<unsigned, ArrayRef<uintptr_t>>>::getHashValue(
721+
std::make_pair(V.size(), V.getData()));
722+
}
723+
static bool isEqual(const SmallBitVector &LHS, const SmallBitVector &RHS) {
724+
if (LHS.isInvalid() || RHS.isInvalid())
725+
return LHS.isInvalid() == RHS.isInvalid();
726+
return LHS == RHS;
727+
}
728+
};
702729
} // end namespace llvm
703730

704731
namespace std {

llvm/unittests/ADT/BitVectorTest.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/ADT/BitVector.h"
10+
#include "llvm/ADT/DenseSet.h"
1011
#include "llvm/ADT/SmallBitVector.h"
1112
#include "gtest/gtest.h"
1213

@@ -1149,4 +1150,38 @@ TYPED_TEST(BitVectorTest, PushBack) {
11491150
EXPECT_EQ(213U, Vec.size());
11501151
EXPECT_EQ(102U, Vec.count());
11511152
}
1153+
1154+
TYPED_TEST(BitVectorTest, DenseSet) {
1155+
DenseSet<TypeParam> Set;
1156+
TypeParam A(10, true);
1157+
auto I = Set.insert(A);
1158+
EXPECT_EQ(true, I.second);
1159+
1160+
TypeParam B(5, true);
1161+
I = Set.insert(B);
1162+
EXPECT_EQ(true, I.second);
1163+
1164+
TypeParam C(20, false);
1165+
C.set(19);
1166+
I = Set.insert(C);
1167+
EXPECT_EQ(true, I.second);
1168+
1169+
TypeParam D;
1170+
EXPECT_DEATH(Set.insert(D),
1171+
"Empty/Tombstone value shouldn't be inserted into map!");
1172+
1173+
EXPECT_EQ(3U, Set.size());
1174+
EXPECT_EQ(1U, Set.count(A));
1175+
EXPECT_EQ(1U, Set.count(B));
1176+
EXPECT_EQ(1U, Set.count(C));
1177+
1178+
EXPECT_EQ(true, Set.erase(B));
1179+
EXPECT_EQ(2U, Set.size());
1180+
1181+
EXPECT_EQ(true, Set.erase(C));
1182+
EXPECT_EQ(1U, Set.size());
1183+
1184+
EXPECT_EQ(true, Set.erase(A));
1185+
EXPECT_EQ(0U, Set.size());
11521186
}
1187+
} // namespace

0 commit comments

Comments
 (0)