HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pointerAndBits.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_TF_POINTER_AND_BITS_H
8 #define PXR_BASE_TF_POINTER_AND_BITS_H
9 
10 #include "pxr/pxr.h"
11 #include "pxr/base/arch/pragmas.h"
12 
13 #include <cstdint>
14 #include <type_traits>
15 #include <utility>
16 
18 
19 // Return true if \p val is a power of two.
20 constexpr bool Tf_IsPow2(uintptr_t val) {
21  return val && !(val & (val - 1));
22 }
23 
24 /// \class TfPointerAndBits
25 ///
26 /// This class stores a T * and a small integer in the space of a T *. The
27 /// number of bits possible to store depends on the alignment of T. The
28 /// number of distinct values representable by the bits and the maximal value
29 /// are exposed via the compile time constants \a NumBitsValues and \a
30 /// MaxValue, respectively.
31 ///
32 /// The bits may be set and retrieved as any integral type. The pointer value
33 /// and the bits value may be set and retrieved independently.
34 ///
35 template <class T>
37 {
38  // Microsoft Visual Studio doesn't like alignof(<abstract-type>).
39  // We'll assume that such an object has a pointer in it (the vtbl
40  // pointer) and use void* for alignment in that case.
41  template <typename U, bool = false>
42  struct _AlignOf {
43  static constexpr uintptr_t value = alignof(U);
44  };
45  template <typename U>
46  struct _AlignOf<U, true> {
47  static constexpr uintptr_t value = alignof(void*);
48  };
49 
50  // Microsoft Visual Studio doesn't like alignof(<abstract-type>).
51  // We'll assume that such an object has a pointer in it (the vtbl
52  // pointer) and use void* for alignment in that case.
53  static constexpr uintptr_t _GetAlign() noexcept {
55  }
56 
57  static constexpr bool _SupportsAtLeastOneBit() noexcept {
58  return _GetAlign() > 1 && Tf_IsPow2(_GetAlign());
59  }
60 
61 public:
62  /// Constructor. Pointer is initialized to null, bits are initialized to
63  /// zero.
64  constexpr TfPointerAndBits() noexcept : _ptrAndBits(0) {
65  static_assert(_SupportsAtLeastOneBit(),
66  "T's alignment does not support any bits");
67  }
68 
69  /// Constructor. Set the pointer to \a p, and the bits to \a bits.
70  constexpr explicit TfPointerAndBits(T *p, uintptr_t bits = 0) noexcept
71  : _ptrAndBits(_Combine(p, bits))
72  {
73  static_assert(_SupportsAtLeastOneBit(),
74  "T's alignment does not support any bits");
75  }
76 
77  constexpr uintptr_t GetMaxValue() const {
78  return _GetAlign() - 1;
79  }
80 
81  constexpr uintptr_t GetNumBitsValues() const {
82  return _GetAlign();
83  }
84 
85  /// Assignment. Leaves bits unmodified.
87  _SetPtr(ptr);
88  return *this;
89  }
90 
91  /// Indirection.
92  constexpr T *operator->() const noexcept {
93  return _GetPtr();
94  }
95 
96  /// Dereference.
97  constexpr T &operator *() const noexcept {
98  return *_GetPtr();
99  }
100 
101  /// Retrieve the stored bits as the integral type \a Integral.
102  template <class Integral>
103  constexpr Integral BitsAs() const noexcept {
106  // XXX: http://bug/DEV-16691
108  return static_cast<Integral>(_GetBits());
110  }
111 
112  /// Set the stored bits. No static range checking is performed.
113  template <class Integral>
114  void SetBits(Integral val) noexcept {
115  _SetBits(static_cast<uintptr_t>(val));
116  }
117 
118  /// Set the pointer value to \a ptr.
119  void Set(T *ptr) noexcept {
120  _SetPtr(ptr);
121  }
122 
123  /// Set the pointer value to \a ptr and the bits to \a val.
124  template <class Integral>
125  void Set(T *ptr, Integral val) noexcept {
126  _ptrAndBits = _Combine(ptr, val);
127  }
128 
129  /// Retrieve the pointer.
130  constexpr T *Get() const noexcept {
131  return _GetPtr();
132  }
133 
134  /// Retrieve the raw underlying value. This can be useful for doing literal
135  /// equality checks between two instances. The only guarantees are that
136  /// this has the same bit pattern as the pointer value if the bits are 0,
137  /// and will compare equal to another instance when both have identical
138  /// pointer and bits values.
139  constexpr uintptr_t GetLiteral() const noexcept {
140  return _AsInt(_ptrAndBits);
141  }
142 
143  /// Swap this PointerAndBits with \a other.
144  void Swap(TfPointerAndBits &other) noexcept {
145  ::std::swap(_ptrAndBits, other._ptrAndBits);
146  }
147 
148 private:
149  constexpr uintptr_t _GetBitMask() const noexcept {
150  return GetMaxValue();
151  }
152 
153  // Combine \a p and \a bits into a single pointer value.
154  constexpr T *_Combine(T *p, uintptr_t bits) const noexcept {
155  return _AsPtr(_AsInt(p) | (bits & _GetBitMask()));
156  }
157 
158  // Cast the pointer \a p to an integral type. This function and _AsPtr are
159  // the only ones that do the dubious compiler-specific casting.
160  constexpr uintptr_t _AsInt(T *p) const noexcept {
161  return (uintptr_t)p;
162  }
163 
164  // Cast the integral \a i to the pointer type. This function and _AsInt are
165  // the only ones that do the dubious compiler-specific casting.
166  constexpr T *_AsPtr(uintptr_t i) const noexcept {
167  return (T *)i;
168  }
169 
170  // Retrieve the held pointer value.
171  constexpr T *_GetPtr() const noexcept {
172  return _AsPtr(_AsInt(_ptrAndBits) & ~_GetBitMask());
173  }
174 
175  // Set the held pointer value.
176  void _SetPtr(T *p) noexcept {
177  _ptrAndBits = _Combine(p, _GetBits());
178  }
179 
180  // Retrieve the held bits value.
181  constexpr uintptr_t _GetBits() const noexcept {
182  return _AsInt(_ptrAndBits) & _GetBitMask();
183  }
184 
185  // Set the held bits value.
186  void _SetBits(uintptr_t bits) noexcept {
187  _ptrAndBits = _Combine(_GetPtr(), bits);
188  }
189 
190  // Single pointer member stores pointer value and bits.
191  T *_ptrAndBits;
192 };
193 
195 
196 #endif // PXR_BASE_TF_POINTER_AND_BITS_H
#define ARCH_PRAGMA_FORCING_TO_BOOL
Definition: pragmas.h:235
TfPointerAndBits & operator=(T *ptr) noexcept
Assignment. Leaves bits unmodified.
PXR_NAMESPACE_OPEN_SCOPE constexpr bool Tf_IsPow2(uintptr_t val)
uint128_t uintptr_t
Definition: format.h:479
void SetBits(Integral val) noexcept
Set the stored bits. No static range checking is performed.
GLsizei const GLfloat * value
Definition: glcorearb.h:824
void Set(T *ptr, Integral val) noexcept
Set the pointer value to ptr and the bits to val.
#define ARCH_PRAGMA_POP
Definition: pragmas.h:159
void swap(T &lhs, T &rhs)
Definition: pugixml.cpp:7440
constexpr T * Get() const noexcept
Retrieve the pointer.
constexpr TfPointerAndBits() noexcept
constexpr T & operator*() const noexcept
Dereference.
constexpr uintptr_t GetLiteral() const noexcept
#define ARCH_PRAGMA_PUSH
Definition: pragmas.h:155
constexpr uintptr_t GetMaxValue() const
constexpr Integral BitsAs() const noexcept
Retrieve the stored bits as the integral type Integral.
void Set(T *ptr) noexcept
Set the pointer value to ptr.
void Swap(TfPointerAndBits &other) noexcept
Swap this PointerAndBits with other.
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
#define ARCH_PRAGMA_MAYBE_UNINITIALIZED
Definition: pragmas.h:175
constexpr uintptr_t GetNumBitsValues() const
auto ptr(T p) -> const void *
Definition: format.h:4331
GLuint GLfloat * val
Definition: glcorearb.h:1608
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
constexpr TfPointerAndBits(T *p, uintptr_t bits=0) noexcept
Constructor. Set the pointer to p, and the bits to bits.
constexpr T * operator->() const noexcept
Indirection.