All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
pointerAndBits.h
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"
12
13#include <cstdint>
14#include <type_traits>
15#include <utility>
16
17PXR_NAMESPACE_OPEN_SCOPE
18
19// Return true if \p val is a power of two.
20constexpr bool Tf_IsPow2(uintptr_t val) {
21 return val && !(val & (val - 1));
22}
23
35template <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 {
54 return _AlignOf<T, std::is_abstract<T>::value>::value;
55 }
56
57 static constexpr bool _SupportsAtLeastOneBit() noexcept {
58 return _GetAlign() > 1 && Tf_IsPow2(_GetAlign());
59 }
60
61public:
64 constexpr TfPointerAndBits() noexcept : _ptrAndBits(0) {
65 static_assert(_SupportsAtLeastOneBit(),
66 "T's alignment does not support any bits");
67 }
68
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
86 TfPointerAndBits &operator=(T *ptr) noexcept {
87 _SetPtr(ptr);
88 return *this;
89 }
90
92 constexpr T *operator->() const noexcept {
93 return _GetPtr();
94 }
95
97 constexpr T &operator *() const noexcept {
98 return *_GetPtr();
99 }
100
102 template <class Integral>
103 constexpr Integral BitsAs() const noexcept {
104 ARCH_PRAGMA_PUSH
105 ARCH_PRAGMA_FORCING_TO_BOOL
106 // XXX: http://bug/DEV-16691
107 ARCH_PRAGMA_MAYBE_UNINITIALIZED
108 return static_cast<Integral>(_GetBits());
109 ARCH_PRAGMA_POP
110 }
111
113 template <class Integral>
114 void SetBits(Integral val) noexcept {
115 _SetBits(static_cast<uintptr_t>(val));
116 }
117
119 void Set(T *ptr) noexcept {
120 _SetPtr(ptr);
121 }
122
124 template <class Integral>
125 void Set(T *ptr, Integral val) noexcept {
126 _ptrAndBits = _Combine(ptr, val);
127 }
128
130 constexpr T *Get() const noexcept {
131 return _GetPtr();
132 }
133
139 constexpr uintptr_t GetLiteral() const noexcept {
140 return _AsInt(_ptrAndBits);
141 }
142
144 void Swap(TfPointerAndBits &other) noexcept {
145 ::std::swap(_ptrAndBits, other._ptrAndBits);
146 }
147
148private:
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
194PXR_NAMESPACE_CLOSE_SCOPE
195
196#endif // PXR_BASE_TF_POINTER_AND_BITS_H
This class stores a T * and a small integer in the space of a T *.
void Set(T *ptr) noexcept
Set the pointer value to ptr.
TfPointerAndBits & operator=(T *ptr) noexcept
Assignment. Leaves bits unmodified.
void SetBits(Integral val) noexcept
Set the stored bits. No static range checking is performed.
constexpr T & operator*() const noexcept
Dereference.
constexpr T * operator->() const noexcept
Indirection.
constexpr TfPointerAndBits() noexcept
Constructor.
void Set(T *ptr, Integral val) noexcept
Set the pointer value to ptr and the bits to val.
constexpr uintptr_t GetLiteral() const noexcept
Retrieve the raw underlying value.
void Swap(TfPointerAndBits &other) noexcept
Swap this PointerAndBits with other.
constexpr T * Get() const noexcept
Retrieve the pointer.
constexpr Integral BitsAs() const noexcept
Retrieve the stored bits as the integral type Integral.
constexpr TfPointerAndBits(T *p, uintptr_t bits=0) noexcept
Constructor. Set the pointer to p, and the bits to bits.
Pragmas for controlling compiler-specific behaviors.