PointerEmbeddedInt.h 4.1 KB

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