Line data Source code
1 : //===- llvm/ADT/PointerEmbeddedInt.h ----------------------------*- C++ -*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 :
10 : #ifndef LLVM_ADT_POINTEREMBEDDEDINT_H
11 : #define LLVM_ADT_POINTEREMBEDDEDINT_H
12 :
13 : #include "llvm/ADT/DenseMapInfo.h"
14 : #include "llvm/Support/MathExtras.h"
15 : #include "llvm/Support/PointerLikeTypeTraits.h"
16 : #include <cassert>
17 : #include <climits>
18 : #include <cstdint>
19 : #include <type_traits>
20 :
21 : namespace llvm {
22 :
23 : /// Utility to embed an integer into a pointer-like type. This is specifically
24 : /// intended to allow embedding integers where fewer bits are required than
25 : /// exist in a pointer, and the integer can participate in abstractions along
26 : /// side other pointer-like types. For example it can be placed into a \c
27 : /// PointerSumType or \c PointerUnion.
28 : ///
29 : /// Note that much like pointers, an integer value of zero has special utility
30 : /// due to boolean conversions. For example, a non-null value can be tested for
31 : /// in the above abstractions without testing the particular active member.
32 : /// Also, the default constructed value zero initializes the integer.
33 : template <typename IntT, int Bits = sizeof(IntT) * CHAR_BIT>
34 : class PointerEmbeddedInt {
35 : uintptr_t Value = 0;
36 :
37 : // Note: This '<' is correct; using '<=' would result in some shifts
38 : // overflowing their storage types.
39 : static_assert(Bits < sizeof(uintptr_t) * CHAR_BIT,
40 : "Cannot embed more bits than we have in a pointer!");
41 :
42 : enum : uintptr_t {
43 : // We shift as many zeros into the value as we can while preserving the
44 : // number of bits desired for the integer.
45 : Shift = sizeof(uintptr_t) * CHAR_BIT - Bits,
46 :
47 : // We also want to be able to mask out the preserved bits for asserts.
48 : Mask = static_cast<uintptr_t>(-1) << Bits
49 : };
50 :
51 : struct RawValueTag {
52 : explicit RawValueTag() = default;
53 : };
54 :
55 : friend struct PointerLikeTypeTraits<PointerEmbeddedInt>;
56 :
57 : explicit PointerEmbeddedInt(uintptr_t Value, RawValueTag) : Value(Value) {}
58 :
59 : public:
60 : PointerEmbeddedInt() = default;
61 :
62 9 : PointerEmbeddedInt(IntT I) { *this = I; }
63 :
64 : PointerEmbeddedInt &operator=(IntT I) {
65 : assert((std::is_signed<IntT>::value ? isInt<Bits>(I) : isUInt<Bits>(I)) &&
66 : "Integer has bits outside those preserved!");
67 1061 : Value = static_cast<uintptr_t>(I) << Shift;
68 : return *this;
69 : }
70 :
71 : // Note that this implicit conversion additionally allows all of the basic
72 : // comparison operators to work transparently, etc.
73 0 : operator IntT() const {
74 : if (std::is_signed<IntT>::value)
75 19 : return static_cast<IntT>(static_cast<intptr_t>(Value) >> Shift);
76 9026477 : return static_cast<IntT>(Value >> Shift);
77 : }
78 0 : };
79 :
80 : // Provide pointer like traits to support use with pointer unions and sum
81 0 : // types.
82 : template <typename IntT, int Bits>
83 0 : struct PointerLikeTypeTraits<PointerEmbeddedInt<IntT, Bits>> {
84 : using T = PointerEmbeddedInt<IntT, Bits>;
85 0 :
86 0 : static inline void *getAsVoidPointer(const T &P) {
87 0 : return reinterpret_cast<void *>(P.Value);
88 0 : }
89 :
90 : static inline T getFromVoidPointer(void *P) {
91 0 : return T(reinterpret_cast<uintptr_t>(P), typename T::RawValueTag());
92 : }
93 0 :
94 : static inline T getFromVoidPointer(const void *P) {
95 0 : return T(reinterpret_cast<uintptr_t>(P), typename T::RawValueTag());
96 : }
97 :
98 0 : enum { NumLowBitsAvailable = T::Shift };
99 : };
100 0 :
101 : // Teach DenseMap how to use PointerEmbeddedInt objects as keys if the Int type
102 : // itself can be a key.
103 : template <typename IntT, int Bits>
104 : struct DenseMapInfo<PointerEmbeddedInt<IntT, Bits>> {
105 : using T = PointerEmbeddedInt<IntT, Bits>;
106 : using IntInfo = DenseMapInfo<IntT>;
107 :
108 : static inline T getEmptyKey() { return IntInfo::getEmptyKey(); }
109 : static inline T getTombstoneKey() { return IntInfo::getTombstoneKey(); }
110 :
111 0 : static unsigned getHashValue(const T &Arg) {
112 0 : return IntInfo::getHashValue(Arg);
113 : }
114 :
115 : static bool isEqual(const T &LHS, const T &RHS) { return LHS == RHS; }
116 : };
117 :
118 : } // end namespace llvm
119 :
120 : #endif // LLVM_ADT_POINTEREMBEDDEDINT_H
|