Loading...
Searching...
No Matches
pointerAndBits.h
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the Apache License, Version 2.0 (the "Apache License")
5// with the following modification; you may not use this file except in
6// compliance with the Apache License and the following modification to it:
7// Section 6. Trademarks. is deleted and replaced with:
8//
9// 6. Trademarks. This License does not grant permission to use the trade
10// names, trademarks, service marks, or product names of the Licensor
11// and its affiliates, except as required to comply with Section 4(c) of
12// the License and to reproduce the content of the NOTICE file.
13//
14// You may obtain a copy of the Apache License at
15//
16// http://www.apache.org/licenses/LICENSE-2.0
17//
18// Unless required by applicable law or agreed to in writing, software
19// distributed under the Apache License with the above modification is
20// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21// KIND, either express or implied. See the Apache License for the specific
22// language governing permissions and limitations under the Apache License.
23//
24#ifndef PXR_BASE_TF_POINTER_AND_BITS_H
25#define PXR_BASE_TF_POINTER_AND_BITS_H
26
27#include "pxr/pxr.h"
29
30#include <cstdint>
31#include <type_traits>
32#include <utility>
33
34PXR_NAMESPACE_OPEN_SCOPE
35
36// Return true if \p val is a power of two.
37constexpr bool Tf_IsPow2(uintptr_t val) {
38 return val && !(val & (val - 1));
39}
40
52template <class T>
54{
55 // Microsoft Visual Studio doesn't like alignof(<abstract-type>).
56 // We'll assume that such an object has a pointer in it (the vtbl
57 // pointer) and use void* for alignment in that case.
58 template <typename U, bool = false>
59 struct _AlignOf {
60 static constexpr uintptr_t value = alignof(U);
61 };
62 template <typename U>
63 struct _AlignOf<U, true> {
64 static constexpr uintptr_t value = alignof(void*);
65 };
66
67 // Microsoft Visual Studio doesn't like alignof(<abstract-type>).
68 // We'll assume that such an object has a pointer in it (the vtbl
69 // pointer) and use void* for alignment in that case.
70 static constexpr uintptr_t _GetAlign() noexcept {
71 return _AlignOf<T, std::is_abstract<T>::value>::value;
72 }
73
74 static constexpr bool _SupportsAtLeastOneBit() noexcept {
75 return _GetAlign() > 1 && Tf_IsPow2(_GetAlign());
76 }
77
78public:
81 constexpr TfPointerAndBits() noexcept : _ptrAndBits(0) {
82 static_assert(_SupportsAtLeastOneBit(),
83 "T's alignment does not support any bits");
84 }
85
87 constexpr explicit TfPointerAndBits(T *p, uintptr_t bits = 0) noexcept
88 : _ptrAndBits(_Combine(p, bits))
89 {
90 static_assert(_SupportsAtLeastOneBit(),
91 "T's alignment does not support any bits");
92 }
93
94 constexpr uintptr_t GetMaxValue() const {
95 return _GetAlign() - 1;
96 }
97
98 constexpr uintptr_t GetNumBitsValues() const {
99 return _GetAlign();
100 }
101
103 TfPointerAndBits &operator=(T *ptr) noexcept {
104 _SetPtr(ptr);
105 return *this;
106 }
107
109 constexpr T *operator->() const noexcept {
110 return _GetPtr();
111 }
112
114 constexpr T &operator *() const noexcept {
115 return *_GetPtr();
116 }
117
119 template <class Integral>
120 constexpr Integral BitsAs() const noexcept {
121 ARCH_PRAGMA_PUSH
122 ARCH_PRAGMA_FORCING_TO_BOOL
123 // XXX: http://bug/DEV-16691
124 ARCH_PRAGMA_MAYBE_UNINITIALIZED
125 return static_cast<Integral>(_GetBits());
126 ARCH_PRAGMA_POP
127 }
128
130 template <class Integral>
131 void SetBits(Integral val) noexcept {
132 _SetBits(static_cast<uintptr_t>(val));
133 }
134
136 void Set(T *ptr) noexcept {
137 _SetPtr(ptr);
138 }
139
141 template <class Integral>
142 void Set(T *ptr, Integral val) noexcept {
143 _ptrAndBits = _Combine(ptr, val);
144 }
145
147 constexpr T *Get() const noexcept {
148 return _GetPtr();
149 }
150
156 constexpr uintptr_t GetLiteral() const noexcept {
157 return _AsInt(_ptrAndBits);
158 }
159
161 void Swap(TfPointerAndBits &other) noexcept {
162 ::std::swap(_ptrAndBits, other._ptrAndBits);
163 }
164
165private:
166 constexpr uintptr_t _GetBitMask() const noexcept {
167 return GetMaxValue();
168 }
169
170 // Combine \a p and \a bits into a single pointer value.
171 constexpr T *_Combine(T *p, uintptr_t bits) const noexcept {
172 return _AsPtr(_AsInt(p) | (bits & _GetBitMask()));
173 }
174
175 // Cast the pointer \a p to an integral type. This function and _AsPtr are
176 // the only ones that do the dubious compiler-specific casting.
177 constexpr uintptr_t _AsInt(T *p) const noexcept {
178 return (uintptr_t)p;
179 }
180
181 // Cast the integral \a i to the pointer type. This function and _AsInt are
182 // the only ones that do the dubious compiler-specific casting.
183 constexpr T *_AsPtr(uintptr_t i) const noexcept {
184 return (T *)i;
185 }
186
187 // Retrieve the held pointer value.
188 constexpr T *_GetPtr() const noexcept {
189 return _AsPtr(_AsInt(_ptrAndBits) & ~_GetBitMask());
190 }
191
192 // Set the held pointer value.
193 void _SetPtr(T *p) noexcept {
194 _ptrAndBits = _Combine(p, _GetBits());
195 }
196
197 // Retrieve the held bits value.
198 constexpr uintptr_t _GetBits() const noexcept {
199 return _AsInt(_ptrAndBits) & _GetBitMask();
200 }
201
202 // Set the held bits value.
203 void _SetBits(uintptr_t bits) noexcept {
204 _ptrAndBits = _Combine(_GetPtr(), bits);
205 }
206
207 // Single pointer member stores pointer value and bits.
208 T *_ptrAndBits;
209};
210
211PXR_NAMESPACE_CLOSE_SCOPE
212
213#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.