diff options
-rw-r--r-- | llvm/include/llvm/ADT/PointerUnion.h | 19 | ||||
-rw-r--r-- | llvm/include/llvm/ADT/TinyPtrVector.h | 38 | ||||
-rw-r--r-- | llvm/unittests/ADT/PointerUnionTest.cpp | 55 | ||||
-rw-r--r-- | llvm/unittests/ADT/TinyPtrVectorTest.cpp | 25 |
4 files changed, 101 insertions, 36 deletions
diff --git a/llvm/include/llvm/ADT/PointerUnion.h b/llvm/include/llvm/ADT/PointerUnion.h index 93533de776b..98c905775a7 100644 --- a/llvm/include/llvm/ADT/PointerUnion.h +++ b/llvm/include/llvm/ADT/PointerUnion.h @@ -160,10 +160,11 @@ class PointerUnion void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int, pointer_union_detail::PointerUnionUIntTraits<PTs...>>, 0, PTs...> { - // The first type is special in some ways, but we don't want PointerUnion to - // be a 'template <typename First, typename ...Rest>' because it's much more - // convenient to have a name for the whole pack. So split off the first type - // here. + // The first type is special because we want to directly cast a pointer to a + // default-initialized union to a pointer to the first type. But we don't + // want PointerUnion to be a 'template <typename First, typename ...Rest>' + // because it's much more convenient to have a name for the whole pack. So + // split off the first type here. using First = typename pointer_union_detail::GetFirstType<PTs...>::type; using Base = typename PointerUnion::PointerUnionMembers; @@ -175,12 +176,7 @@ public: /// Test if the pointer held in the union is null, regardless of /// which type it is. - bool isNull() const { - // Convert from the void* to one of the pointer types, to make sure that - // we recursively strip off low bits if we have a nested PointerUnion. - return !PointerLikeTypeTraits<First>::getFromVoidPointer( - this->Val.getPointer()); - } + bool isNull() const { return !this->Val.getPointer(); } explicit operator bool() const { return !isNull(); } @@ -219,7 +215,8 @@ public: First *getAddrOfPtr1() { assert(is<First>() && "Val is not the first pointer"); assert( - get<First>() == this->Val.getPointer() && + PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) == + this->Val.getPointer() && "Can't get the address because PointerLikeTypeTraits changes the ptr"); return const_cast<First *>( reinterpret_cast<const First *>(this->Val.getAddrOfPointer())); diff --git a/llvm/include/llvm/ADT/TinyPtrVector.h b/llvm/include/llvm/ADT/TinyPtrVector.h index ac82451a9b2..6b76d35d4e9 100644 --- a/llvm/include/llvm/ADT/TinyPtrVector.h +++ b/llvm/include/llvm/ADT/TinyPtrVector.h @@ -31,6 +31,10 @@ class TinyPtrVector { public: using VecTy = SmallVector<EltTy, 4>; using value_type = typename VecTy::value_type; + // EltTy must be the first pointer type so that is<EltTy> is true for the + // default-constructed PtrUnion. This allows an empty TinyPtrVector to + // naturally vend a begin/end iterator of type EltTy* without an additional + // check for the empty state. using PtrUnion = PointerUnion<EltTy, VecTy *>; private: @@ -96,14 +100,14 @@ public: if (RHS.Val.template is<EltTy>()) { V->clear(); V->push_back(RHS.front()); - RHS.Val = (EltTy)nullptr; + RHS.Val = EltTy(); return *this; } delete V; } Val = RHS.Val; - RHS.Val = (EltTy)nullptr; + RHS.Val = EltTy(); return *this; } @@ -213,9 +217,9 @@ public: EltTy operator[](unsigned i) const { assert(!Val.isNull() && "can't index into an empty vector"); - if (EltTy V = Val.template dyn_cast<EltTy>()) { + if (Val.template is<EltTy>()) { assert(i == 0 && "tinyvector index out of range"); - return V; + return Val.template get<EltTy>(); } assert(i < Val.template get<VecTy*>()->size() && @@ -225,29 +229,29 @@ public: EltTy front() const { assert(!empty() && "vector empty"); - if (EltTy V = Val.template dyn_cast<EltTy>()) - return V; + if (Val.template is<EltTy>()) + return Val.template get<EltTy>(); return Val.template get<VecTy*>()->front(); } EltTy back() const { assert(!empty() && "vector empty"); - if (EltTy V = Val.template dyn_cast<EltTy>()) - return V; + if (Val.template is<EltTy>()) + return Val.template get<EltTy>(); return Val.template get<VecTy*>()->back(); } void push_back(EltTy NewVal) { - assert(NewVal && "Can't add a null value"); - // If we have nothing, add something. if (Val.isNull()) { Val = NewVal; + assert(!Val.isNull() && "Can't add a null value"); return; } // If we have a single value, convert to a vector. - if (EltTy V = Val.template dyn_cast<EltTy>()) { + if (Val.template is<EltTy>()) { + EltTy V = Val.template get<EltTy>(); Val = new VecTy(); Val.template get<VecTy*>()->push_back(V); } @@ -267,7 +271,7 @@ public: void clear() { // If we have a single value, convert to empty. if (Val.template is<EltTy>()) { - Val = (EltTy)nullptr; + Val = EltTy(); } else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) { // If we have a vector form, just clear it. Vec->clear(); @@ -282,7 +286,7 @@ public: // If we have a single value, convert to empty. if (Val.template is<EltTy>()) { if (I == begin()) - Val = (EltTy)nullptr; + Val = EltTy(); } else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) { // multiple items in a vector; just do the erase, there is no // benefit to collapsing back to a pointer @@ -298,7 +302,7 @@ public: if (Val.template is<EltTy>()) { if (S == begin() && S != E) - Val = (EltTy)nullptr; + Val = EltTy(); } else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) { return Vec->erase(S, E); } @@ -313,7 +317,8 @@ public: return std::prev(end()); } assert(!Val.isNull() && "Null value with non-end insert iterator."); - if (EltTy V = Val.template dyn_cast<EltTy>()) { + if (Val.template is<EltTy>()) { + EltTy V = Val.template get<EltTy>(); assert(I == begin()); Val = Elt; push_back(V); @@ -339,7 +344,8 @@ public: } Val = new VecTy(); - } else if (EltTy V = Val.template dyn_cast<EltTy>()) { + } else if (Val.template is<EltTy>()) { + EltTy V = Val.template get<EltTy>(); Val = new VecTy(); Val.template get<VecTy*>()->push_back(V); } diff --git a/llvm/unittests/ADT/PointerUnionTest.cpp b/llvm/unittests/ADT/PointerUnionTest.cpp index cd6e980e9a2..0a88114ede8 100644 --- a/llvm/unittests/ADT/PointerUnionTest.cpp +++ b/llvm/unittests/ADT/PointerUnionTest.cpp @@ -13,14 +13,25 @@ using namespace llvm; namespace { typedef PointerUnion<int *, float *> PU; +typedef PointerUnion3<int *, float *, long long *> PU3; +typedef PointerUnion4<int *, float *, long long *, double *> PU4; struct PointerUnionTest : public testing::Test { float f; int i; + double d; + long long l; PU a, b, c, n; - - PointerUnionTest() : f(3.14f), i(42), a(&f), b(&i), c(&i), n() {} + PU3 i3, f3, l3; + PU4 i4, f4, l4, d4; + PU4 i4null, f4null, l4null, d4null; + + PointerUnionTest() + : f(3.14f), i(42), d(3.14), l(42), a(&f), b(&i), c(&i), n(), i3(&i), + f3(&f), l3(&l), i4(&i), f4(&f), l4(&l), d4(&d), i4null((int *)nullptr), + f4null((float *)nullptr), l4null((long long *)nullptr), + d4null((double *)nullptr) {} }; TEST_F(PointerUnionTest, Comparison) { @@ -32,6 +43,19 @@ TEST_F(PointerUnionTest, Comparison) { EXPECT_FALSE(b != c); EXPECT_TRUE(b != n); EXPECT_FALSE(b == n); + EXPECT_TRUE(i3 == i3); + EXPECT_FALSE(i3 != i3); + EXPECT_TRUE(i3 != f3); + EXPECT_TRUE(f3 != l3); + EXPECT_TRUE(i4 == i4); + EXPECT_FALSE(i4 != i4); + EXPECT_TRUE(i4 != f4); + EXPECT_TRUE(i4 != l4); + EXPECT_TRUE(f4 != l4); + EXPECT_TRUE(l4 != d4); + EXPECT_TRUE(i4null != f4null); + EXPECT_TRUE(i4null != l4null); + EXPECT_TRUE(i4null != d4null); } TEST_F(PointerUnionTest, Null) { @@ -51,6 +75,17 @@ TEST_F(PointerUnionTest, Null) { b = nullptr; EXPECT_EQ(n, b); EXPECT_NE(b, c); + EXPECT_FALSE(i3.isNull()); + EXPECT_FALSE(f3.isNull()); + EXPECT_FALSE(l3.isNull()); + EXPECT_FALSE(i4.isNull()); + EXPECT_FALSE(f4.isNull()); + EXPECT_FALSE(l4.isNull()); + EXPECT_FALSE(d4.isNull()); + EXPECT_TRUE(i4null.isNull()); + EXPECT_TRUE(f4null.isNull()); + EXPECT_TRUE(l4null.isNull()); + EXPECT_TRUE(d4null.isNull()); } TEST_F(PointerUnionTest, Is) { @@ -60,6 +95,17 @@ TEST_F(PointerUnionTest, Is) { EXPECT_FALSE(b.is<float *>()); EXPECT_TRUE(n.is<int *>()); EXPECT_FALSE(n.is<float *>()); + EXPECT_TRUE(i3.is<int *>()); + EXPECT_TRUE(f3.is<float *>()); + EXPECT_TRUE(l3.is<long long *>()); + EXPECT_TRUE(i4.is<int *>()); + EXPECT_TRUE(f4.is<float *>()); + EXPECT_TRUE(l4.is<long long *>()); + EXPECT_TRUE(d4.is<double *>()); + EXPECT_TRUE(i4null.is<int *>()); + EXPECT_TRUE(f4null.is<float *>()); + EXPECT_TRUE(l4null.is<long long *>()); + EXPECT_TRUE(d4null.is<double *>()); } TEST_F(PointerUnionTest, Get) { @@ -105,4 +151,9 @@ TEST_F(PointerUnionTest, ManyElements) { EXPECT_TRUE(a != PU8(&a0)); } +TEST_F(PointerUnionTest, GetAddrOfPtr1) { + EXPECT_TRUE((void *)b.getAddrOfPtr1() == (void *)&b); + EXPECT_TRUE((void *)n.getAddrOfPtr1() == (void *)&n); +} + } // end anonymous namespace diff --git a/llvm/unittests/ADT/TinyPtrVectorTest.cpp b/llvm/unittests/ADT/TinyPtrVectorTest.cpp index c8c00d94736..f88534787c9 100644 --- a/llvm/unittests/ADT/TinyPtrVectorTest.cpp +++ b/llvm/unittests/ADT/TinyPtrVectorTest.cpp @@ -22,12 +22,21 @@ using namespace llvm; namespace { +template <typename T> struct RemovePointer : std::remove_pointer<T> {}; + +template <typename PointerTy, unsigned IntBits, typename IntType, + typename PtrTraits, typename Info> +struct RemovePointer< + PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>> { + typedef typename RemovePointer<PointerTy>::type type; +}; template <typename VectorT> class TinyPtrVectorTest : public testing::Test { protected: typedef typename VectorT::value_type PtrT; - typedef typename std::remove_pointer<PtrT>::type ValueT; + typedef typename RemovePointer<PtrT>::type ValueT; + using PtrTraits = PointerLikeTypeTraits<PtrT>; VectorT V; VectorT V2; @@ -37,11 +46,13 @@ protected: TinyPtrVectorTest() { for (size_t i = 0, e = array_lengthof(TestValues); i != e; ++i) - TestPtrs.push_back(&TestValues[i]); + TestPtrs.push_back(PtrT(&TestValues[i])); std::shuffle(TestPtrs.begin(), TestPtrs.end(), std::mt19937{}); } + PtrT makePtr(ValueT *V) { return PtrT(V); } + ArrayRef<PtrT> testArray(size_t N) { return makeArrayRef(&TestPtrs[0], N); } @@ -69,9 +80,9 @@ protected: } }; -typedef ::testing::Types<TinyPtrVector<int*>, - TinyPtrVector<double*> - > TinyPtrVectorTestTypes; +typedef ::testing::Types<TinyPtrVector<int *>, TinyPtrVector<double *>, + TinyPtrVector<PointerIntPair<int *, 1>>> + TinyPtrVectorTestTypes; TYPED_TEST_CASE(TinyPtrVectorTest, TinyPtrVectorTestTypes); TYPED_TEST(TinyPtrVectorTest, EmptyTest) { @@ -95,8 +106,8 @@ TYPED_TEST(TinyPtrVectorTest, PushPopBack) { this->expectValues(this->V, this->testArray(4)); this->V.pop_back(); this->expectValues(this->V, this->testArray(3)); - this->TestPtrs[3] = &this->TestValues[42]; - this->TestPtrs[4] = &this->TestValues[43]; + this->TestPtrs[3] = this->makePtr(&this->TestValues[42]); + this->TestPtrs[4] = this->makePtr(&this->TestValues[43]); this->V.push_back(this->TestPtrs[3]); this->expectValues(this->V, this->testArray(4)); this->V.push_back(this->TestPtrs[4]); |