PointerEmbeddedInt.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- llvm/ADT/PointerEmbeddedInt.h ----------------------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_ADT_POINTEREMBEDDEDINT_H
  14. #define LLVM_ADT_POINTEREMBEDDEDINT_H
  15. #include "llvm/ADT/DenseMapInfo.h"
  16. #include "llvm/Support/MathExtras.h"
  17. #include "llvm/Support/PointerLikeTypeTraits.h"
  18. #include <cassert>
  19. #include <climits>
  20. #include <cstdint>
  21. #include <type_traits>
  22. namespace llvm {
  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. // Note: This '<' is correct; using '<=' would result in some shifts
  37. // overflowing their storage types.
  38. static_assert(Bits < sizeof(uintptr_t) * CHAR_BIT,
  39. "Cannot embed more bits than we have in a pointer!");
  40. enum : uintptr_t {
  41. // We shift as many zeros into the value as we can while preserving the
  42. // number of bits desired for the integer.
  43. Shift = sizeof(uintptr_t) * CHAR_BIT - Bits,
  44. // We also want to be able to mask out the preserved bits for asserts.
  45. Mask = static_cast<uintptr_t>(-1) << Bits
  46. };
  47. struct RawValueTag {
  48. explicit RawValueTag() = default;
  49. };
  50. friend struct PointerLikeTypeTraits<PointerEmbeddedInt>;
  51. explicit PointerEmbeddedInt(uintptr_t Value, RawValueTag) : Value(Value) {}
  52. public:
  53. PointerEmbeddedInt() = default;
  54. PointerEmbeddedInt(IntT I) { *this = I; }
  55. PointerEmbeddedInt &operator=(IntT I) {
  56. assert((std::is_signed<IntT>::value ? isInt<Bits>(I) : isUInt<Bits>(I)) &&
  57. "Integer has bits outside those preserved!");
  58. Value = static_cast<uintptr_t>(I) << Shift;
  59. return *this;
  60. }
  61. // Note that this implicit conversion additionally allows all of the basic
  62. // comparison operators to work transparently, etc.
  63. operator IntT() const {
  64. if (std::is_signed<IntT>::value)
  65. return static_cast<IntT>(static_cast<intptr_t>(Value) >> Shift);
  66. return static_cast<IntT>(Value >> Shift);
  67. }
  68. };
  69. // Provide pointer like traits to support use with pointer unions and sum
  70. // types.
  71. template <typename IntT, int Bits>
  72. struct PointerLikeTypeTraits<PointerEmbeddedInt<IntT, Bits>> {
  73. using T = PointerEmbeddedInt<IntT, Bits>;
  74. static inline void *getAsVoidPointer(const T &P) {
  75. return reinterpret_cast<void *>(P.Value);
  76. }
  77. static inline T getFromVoidPointer(void *P) {
  78. return T(reinterpret_cast<uintptr_t>(P), typename T::RawValueTag());
  79. }
  80. static inline T getFromVoidPointer(const void *P) {
  81. return T(reinterpret_cast<uintptr_t>(P), typename T::RawValueTag());
  82. }
  83. static constexpr int NumLowBitsAvailable = T::Shift;
  84. };
  85. // Teach DenseMap how to use PointerEmbeddedInt objects as keys if the Int type
  86. // itself can be a key.
  87. template <typename IntT, int Bits>
  88. struct DenseMapInfo<PointerEmbeddedInt<IntT, Bits>> {
  89. using T = PointerEmbeddedInt<IntT, Bits>;
  90. using IntInfo = DenseMapInfo<IntT>;
  91. static inline T getEmptyKey() { return IntInfo::getEmptyKey(); }
  92. static inline T getTombstoneKey() { return IntInfo::getTombstoneKey(); }
  93. static unsigned getHashValue(const T &Arg) {
  94. return IntInfo::getHashValue(Arg);
  95. }
  96. static bool isEqual(const T &LHS, const T &RHS) { return LHS == RHS; }
  97. };
  98. } // end namespace llvm
  99. #endif // LLVM_ADT_POINTEREMBEDDEDINT_H
  100. #ifdef __GNUC__
  101. #pragma GCC diagnostic pop
  102. #endif