Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 1 | //===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===// |
| 2 | // |
Andrew Walbran | 16937d0 | 2019-10-22 13:54:20 +0100 | [diff] [blame] | 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file defines the PointerUnion class, which is a discriminated union of |
| 10 | // pointer types. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef LLVM_ADT_POINTERUNION_H |
| 15 | #define LLVM_ADT_POINTERUNION_H |
| 16 | |
| 17 | #include "llvm/ADT/DenseMapInfo.h" |
| 18 | #include "llvm/ADT/PointerIntPair.h" |
| 19 | #include "llvm/Support/PointerLikeTypeTraits.h" |
| 20 | #include <cassert> |
| 21 | #include <cstddef> |
| 22 | #include <cstdint> |
| 23 | |
| 24 | namespace llvm { |
| 25 | |
| 26 | template <typename T> struct PointerUnionTypeSelectorReturn { |
| 27 | using Return = T; |
| 28 | }; |
| 29 | |
| 30 | /// Get a type based on whether two types are the same or not. |
| 31 | /// |
| 32 | /// For: |
| 33 | /// |
| 34 | /// \code |
| 35 | /// using Ret = typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return; |
| 36 | /// \endcode |
| 37 | /// |
| 38 | /// Ret will be EQ type if T1 is same as T2 or NE type otherwise. |
| 39 | template <typename T1, typename T2, typename RET_EQ, typename RET_NE> |
| 40 | struct PointerUnionTypeSelector { |
| 41 | using Return = typename PointerUnionTypeSelectorReturn<RET_NE>::Return; |
| 42 | }; |
| 43 | |
| 44 | template <typename T, typename RET_EQ, typename RET_NE> |
| 45 | struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> { |
| 46 | using Return = typename PointerUnionTypeSelectorReturn<RET_EQ>::Return; |
| 47 | }; |
| 48 | |
| 49 | template <typename T1, typename T2, typename RET_EQ, typename RET_NE> |
| 50 | struct PointerUnionTypeSelectorReturn< |
| 51 | PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>> { |
| 52 | using Return = |
| 53 | typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return; |
| 54 | }; |
| 55 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 56 | namespace pointer_union_detail { |
| 57 | constexpr int constexprMin(int a, int b) { return a < b ? a : b; } |
| 58 | /// Determine the number of bits required to store integers with values < n. |
| 59 | /// This is ceil(log2(n)). |
| 60 | constexpr int bitsRequired(unsigned n) { |
| 61 | return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0; |
| 62 | } |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 63 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 64 | // FIXME: In C++14, replace this with |
| 65 | // std::min({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...}) |
| 66 | template <typename T> constexpr int lowBitsAvailable() { |
| 67 | return PointerLikeTypeTraits<T>::NumLowBitsAvailable; |
| 68 | } |
| 69 | template <typename T1, typename T2, typename... Ts> |
| 70 | constexpr int lowBitsAvailable() { |
| 71 | return constexprMin(lowBitsAvailable<T1>(), lowBitsAvailable<T2, Ts...>()); |
| 72 | } |
| 73 | |
| 74 | /// Find the index of a type in a list of types. TypeIndex<T, Us...>::Index |
| 75 | /// is the index of T in Us, or sizeof...(Us) if T does not appear in the |
| 76 | /// list. |
| 77 | template <typename T, typename ...Us> struct TypeIndex; |
| 78 | template <typename T, typename ...Us> struct TypeIndex<T, T, Us...> { |
| 79 | static constexpr int Index = 0; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 80 | }; |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 81 | template <typename T, typename U, typename... Us> |
| 82 | struct TypeIndex<T, U, Us...> { |
| 83 | static constexpr int Index = 1 + TypeIndex<T, Us...>::Index; |
| 84 | }; |
| 85 | template <typename T> struct TypeIndex<T> { |
| 86 | static constexpr int Index = 0; |
| 87 | }; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 88 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 89 | /// Find the first type in a list of types. |
| 90 | template <typename T, typename...> struct GetFirstType { |
| 91 | using type = T; |
| 92 | }; |
| 93 | |
| 94 | /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion |
| 95 | /// for the template arguments. |
| 96 | template <typename ...PTs> class PointerUnionUIntTraits { |
| 97 | public: |
| 98 | static inline void *getAsVoidPointer(void *P) { return P; } |
| 99 | static inline void *getFromVoidPointer(void *P) { return P; } |
| 100 | static constexpr int NumLowBitsAvailable = lowBitsAvailable<PTs...>(); |
| 101 | }; |
| 102 | |
| 103 | /// Implement assigment in terms of construction. |
| 104 | template <typename Derived, typename T> struct AssignableFrom { |
| 105 | Derived &operator=(T t) { |
| 106 | return static_cast<Derived &>(*this) = Derived(t); |
| 107 | } |
| 108 | }; |
| 109 | |
| 110 | template <typename Derived, typename ValTy, int I, typename ...Types> |
| 111 | class PointerUnionMembers; |
| 112 | |
| 113 | template <typename Derived, typename ValTy, int I> |
| 114 | class PointerUnionMembers<Derived, ValTy, I> { |
| 115 | protected: |
| 116 | ValTy Val; |
| 117 | PointerUnionMembers() = default; |
| 118 | PointerUnionMembers(ValTy Val) : Val(Val) {} |
| 119 | |
| 120 | friend struct PointerLikeTypeTraits<Derived>; |
| 121 | }; |
| 122 | |
| 123 | template <typename Derived, typename ValTy, int I, typename Type, |
| 124 | typename ...Types> |
| 125 | class PointerUnionMembers<Derived, ValTy, I, Type, Types...> |
| 126 | : public PointerUnionMembers<Derived, ValTy, I + 1, Types...> { |
| 127 | using Base = PointerUnionMembers<Derived, ValTy, I + 1, Types...>; |
| 128 | public: |
| 129 | using Base::Base; |
| 130 | PointerUnionMembers() = default; |
| 131 | PointerUnionMembers(Type V) |
| 132 | : Base(ValTy(const_cast<void *>( |
| 133 | PointerLikeTypeTraits<Type>::getAsVoidPointer(V)), |
| 134 | I)) {} |
| 135 | |
| 136 | using Base::operator=; |
| 137 | Derived &operator=(Type V) { |
| 138 | this->Val = ValTy( |
| 139 | const_cast<void *>(PointerLikeTypeTraits<Type>::getAsVoidPointer(V)), |
| 140 | I); |
| 141 | return static_cast<Derived &>(*this); |
| 142 | }; |
| 143 | }; |
| 144 | } |
| 145 | |
| 146 | /// A discriminated union of two or more pointer types, with the discriminator |
| 147 | /// in the low bit of the pointer. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 148 | /// |
| 149 | /// This implementation is extremely efficient in space due to leveraging the |
| 150 | /// low bits of the pointer, while exposing a natural and type-safe API. |
| 151 | /// |
| 152 | /// Common use patterns would be something like this: |
| 153 | /// PointerUnion<int*, float*> P; |
| 154 | /// P = (int*)0; |
| 155 | /// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0" |
| 156 | /// X = P.get<int*>(); // ok. |
| 157 | /// Y = P.get<float*>(); // runtime assertion failure. |
| 158 | /// Z = P.get<double*>(); // compile time failure. |
| 159 | /// P = (float*)0; |
| 160 | /// Y = P.get<float*>(); // ok. |
| 161 | /// X = P.get<int*>(); // runtime assertion failure. |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 162 | template <typename... PTs> |
| 163 | class PointerUnion |
| 164 | : public pointer_union_detail::PointerUnionMembers< |
| 165 | PointerUnion<PTs...>, |
| 166 | PointerIntPair< |
| 167 | void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int, |
| 168 | pointer_union_detail::PointerUnionUIntTraits<PTs...>>, |
| 169 | 0, PTs...> { |
| 170 | // The first type is special in some ways, but we don't want PointerUnion to |
| 171 | // be a 'template <typename First, typename ...Rest>' because it's much more |
| 172 | // convenient to have a name for the whole pack. So split off the first type |
| 173 | // here. |
| 174 | using First = typename pointer_union_detail::GetFirstType<PTs...>::type; |
| 175 | using Base = typename PointerUnion::PointerUnionMembers; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 176 | |
| 177 | public: |
| 178 | PointerUnion() = default; |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 179 | |
| 180 | PointerUnion(std::nullptr_t) : PointerUnion() {} |
| 181 | using Base::Base; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 182 | |
| 183 | /// Test if the pointer held in the union is null, regardless of |
| 184 | /// which type it is. |
| 185 | bool isNull() const { |
| 186 | // Convert from the void* to one of the pointer types, to make sure that |
| 187 | // we recursively strip off low bits if we have a nested PointerUnion. |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 188 | return !PointerLikeTypeTraits<First>::getFromVoidPointer( |
| 189 | this->Val.getPointer()); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 190 | } |
| 191 | |
| 192 | explicit operator bool() const { return !isNull(); } |
| 193 | |
| 194 | /// Test if the Union currently holds the type matching T. |
| 195 | template <typename T> int is() const { |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 196 | constexpr int Index = pointer_union_detail::TypeIndex<T, PTs...>::Index; |
| 197 | static_assert(Index < sizeof...(PTs), |
| 198 | "PointerUnion::is<T> given type not in the union"); |
| 199 | return this->Val.getInt() == Index; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 200 | } |
| 201 | |
| 202 | /// Returns the value of the specified pointer type. |
| 203 | /// |
| 204 | /// If the specified pointer type is incorrect, assert. |
| 205 | template <typename T> T get() const { |
| 206 | assert(is<T>() && "Invalid accessor called"); |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 207 | return PointerLikeTypeTraits<T>::getFromVoidPointer(this->Val.getPointer()); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 208 | } |
| 209 | |
| 210 | /// Returns the current pointer if it is of the specified pointer type, |
| 211 | /// otherwises returns null. |
| 212 | template <typename T> T dyn_cast() const { |
| 213 | if (is<T>()) |
| 214 | return get<T>(); |
| 215 | return T(); |
| 216 | } |
| 217 | |
| 218 | /// If the union is set to the first pointer type get an address pointing to |
| 219 | /// it. |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 220 | First const *getAddrOfPtr1() const { |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 221 | return const_cast<PointerUnion *>(this)->getAddrOfPtr1(); |
| 222 | } |
| 223 | |
| 224 | /// If the union is set to the first pointer type get an address pointing to |
| 225 | /// it. |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 226 | First *getAddrOfPtr1() { |
| 227 | assert(is<First>() && "Val is not the first pointer"); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 228 | assert( |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 229 | get<First>() == this->Val.getPointer() && |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 230 | "Can't get the address because PointerLikeTypeTraits changes the ptr"); |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 231 | return const_cast<First *>( |
| 232 | reinterpret_cast<const First *>(this->Val.getAddrOfPointer())); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 233 | } |
| 234 | |
| 235 | /// Assignment from nullptr which just clears the union. |
| 236 | const PointerUnion &operator=(std::nullptr_t) { |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 237 | this->Val.initWithPointer(nullptr); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 238 | return *this; |
| 239 | } |
| 240 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 241 | /// Assignment from elements of the union. |
| 242 | using Base::operator=; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 243 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 244 | void *getOpaqueValue() const { return this->Val.getOpaqueValue(); } |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 245 | static inline PointerUnion getFromOpaqueValue(void *VP) { |
| 246 | PointerUnion V; |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 247 | V.Val = decltype(V.Val)::getFromOpaqueValue(VP); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 248 | return V; |
| 249 | } |
| 250 | }; |
| 251 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 252 | template <typename ...PTs> |
| 253 | bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) { |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 254 | return lhs.getOpaqueValue() == rhs.getOpaqueValue(); |
| 255 | } |
| 256 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 257 | template <typename ...PTs> |
| 258 | bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) { |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 259 | return lhs.getOpaqueValue() != rhs.getOpaqueValue(); |
| 260 | } |
| 261 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 262 | template <typename ...PTs> |
| 263 | bool operator<(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) { |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 264 | return lhs.getOpaqueValue() < rhs.getOpaqueValue(); |
| 265 | } |
| 266 | |
| 267 | // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has |
| 268 | // # low bits available = min(PT1bits,PT2bits)-1. |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 269 | template <typename ...PTs> |
| 270 | struct PointerLikeTypeTraits<PointerUnion<PTs...>> { |
| 271 | static inline void *getAsVoidPointer(const PointerUnion<PTs...> &P) { |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 272 | return P.getOpaqueValue(); |
| 273 | } |
| 274 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 275 | static inline PointerUnion<PTs...> getFromVoidPointer(void *P) { |
| 276 | return PointerUnion<PTs...>::getFromOpaqueValue(P); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 277 | } |
| 278 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 279 | // The number of bits available are the min of the pointer types minus the |
| 280 | // bits needed for the discriminator. |
| 281 | static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits<decltype( |
| 282 | PointerUnion<PTs...>::Val)>::NumLowBitsAvailable; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 283 | }; |
| 284 | |
| 285 | /// A pointer union of three pointer types. See documentation for PointerUnion |
| 286 | /// for usage. |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 287 | template <typename PT1, typename PT2, typename PT3> |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 288 | using PointerUnion3 = PointerUnion<PT1, PT2, PT3>; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 289 | |
| 290 | /// A pointer union of four pointer types. See documentation for PointerUnion |
| 291 | /// for usage. |
| 292 | template <typename PT1, typename PT2, typename PT3, typename PT4> |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 293 | using PointerUnion4 = PointerUnion<PT1, PT2, PT3, PT4>; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 294 | |
| 295 | // Teach DenseMap how to use PointerUnions as keys. |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 296 | template <typename ...PTs> struct DenseMapInfo<PointerUnion<PTs...>> { |
| 297 | using Union = PointerUnion<PTs...>; |
| 298 | using FirstInfo = |
| 299 | DenseMapInfo<typename pointer_union_detail::GetFirstType<PTs...>::type>; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 300 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 301 | static inline Union getEmptyKey() { return Union(FirstInfo::getEmptyKey()); } |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 302 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 303 | static inline Union getTombstoneKey() { |
| 304 | return Union(FirstInfo::getTombstoneKey()); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 305 | } |
| 306 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 307 | static unsigned getHashValue(const Union &UnionVal) { |
| 308 | intptr_t key = (intptr_t)UnionVal.getOpaqueValue(); |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 309 | return DenseMapInfo<intptr_t>::getHashValue(key); |
| 310 | } |
| 311 | |
Andrew Walbran | 3d2c197 | 2020-04-07 12:24:26 +0100 | [diff] [blame^] | 312 | static bool isEqual(const Union &LHS, const Union &RHS) { |
| 313 | return LHS == RHS; |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 314 | } |
| 315 | }; |
| 316 | |
| 317 | } // end namespace llvm |
| 318 | |
| 319 | #endif // LLVM_ADT_POINTERUNION_H |