Loading...
Searching...
No Matches
fixedSizePolymorphicHolder.h
Go to the documentation of this file.
1//
2// Copyright 2025 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_EXEC_ESF_FIXED_SIZE_POLYMORPHIC_HOLDER_H
8#define PXR_EXEC_ESF_FIXED_SIZE_POLYMORPHIC_HOLDER_H
9
11
12#include "pxr/pxr.h"
13
14#include "pxr/exec/esf/api.h"
15
17#include "pxr/base/tf/tf.h"
18
19#include <cstddef>
20#include <new>
21#include <type_traits>
22#include <utility>
23
24PXR_NAMESPACE_OPEN_SCOPE
25
32{
33public:
34 ESF_API virtual ~EsfFixedSizePolymorphicBase();
35
36private:
37 template <class Base, size_t BufferSize>
39
40 // Copies this object to the storage of another
41 // EsfFixedSizePolymorphicHolder.
42 //
43 // This class provides a default implementation so that derived types can be
44 // instantiated without having to override it. The proper overridden
45 // implementation will be defined by EsfFixedSizePolymorphicHolder.
46 //
47 ESF_API virtual void _CopyTo(std::byte *storage) const;
48
49 // Moves this object to the storage of another
50 // EsfFixedSizePolymorphicHolder.
51 //
52 // This class provides a default implementation so that derived types can be
53 // instantiated without having to override it. The proper overridden
54 // implementation will be defined by EsfFixedSizePolymorphicHolder.
55 //
56 ESF_API virtual void _MoveTo(std::byte *storage);
57};
58
76template <class Base, size_t BufferSize = sizeof(Base)>
78{
79 static_assert(std::is_base_of_v<EsfFixedSizePolymorphicBase, Base>);
80 constexpr static size_t _REQUIRED_ALIGNMENT = alignof(Base);
81
82public:
84
89
98 template <class Derived, class... Args>
100 std::in_place_type_t<Derived> derivedTypeHint, Args &&...args);
101
106 other->_CopyTo(_storage);
107 }
108
116 other->_MoveTo(_storage);
117 }
118
122 Get()->~Base();
123 }
124
131 This &operator=(const This &other) {
132 if (this != &other) {
133 Get()->~Base();
134 other->_CopyTo(_storage);
135 }
136 return *this;
137 }
138
146 This &operator=(This &&other) {
147 if (this != &other) {
148 Get()->~Base();
149 other->_MoveTo(_storage);
150 }
151 return *this;
152 }
153
159 inline Base *Get() {
160 return reinterpret_cast<Base *>(_storage);
161 }
162
163 inline const Base *Get() const {
164 return reinterpret_cast<const Base *>(_storage);
165 }
166
167 inline Base *operator->() {
168 return Get();
169 }
170
171 inline const Base *operator->() const {
172 return Get();
173 }
174
175 inline Base &operator*() {
176 return *Get();
177 }
178
179 inline const Base &operator*() const {
180 return *Get();
181 }
183
191 {
192 template <class Derived>
193 constexpr static bool FITS_IN_BUFFER = sizeof(Derived) <= BufferSize;
194
195 template <class Derived>
196 constexpr static bool DERIVES_FROM_BASE =
197 std::is_base_of_v<Base, Derived>;
198
199 template <class Derived>
200 constexpr static bool HAS_ALIGNMENT =
201 alignof(Derived) == _REQUIRED_ALIGNMENT;
202
209 template <class Derived>
210 static bool HasBaseAtSameAddress(const Derived &derived);
211 };
212
213private:
214 // Implements the _CopyTo and _MoveTo methods for a derived type.
215 template <class Derived>
216 class _Holder : public Derived
217 {
218 public:
219 // Constructs a Derived instance from the provided constructor Args.
220 template <class... Args>
221 _Holder(Args &&...args) : Derived(std::forward<Args>(args)...) {
223 }
224
225 private:
226 void _CopyTo(std::byte *storage) const final {
227 const Derived *thisDerived = static_cast<const Derived *>(this);
228 ::new (static_cast<void *>(storage)) _Holder<Derived>(*thisDerived);
229 }
230
231 void _MoveTo(std::byte *storage) final {
232 Derived *thisDerived = static_cast<Derived *>(this);
233 ::new (static_cast<void *>(storage)) _Holder<Derived>(
234 std::move(*thisDerived));
235 }
236 };
237
238 // Held instances are emplaced in this byte array.
239 alignas(_REQUIRED_ALIGNMENT) std::byte _storage[BufferSize];
240};
241
242template <class Base, size_t BufferSize>
243template <class Derived, class... Args>
245 std::in_place_type_t<Derived> derivedTypeHint, Args &&...args)
246{
247 TF_UNUSED(derivedTypeHint);
248
249 static_assert(
250 Compatibility::template FITS_IN_BUFFER<Derived>,
251 "The size of the derived type is larger than the availble "
252 "storage.");
253 static_assert(
254 Compatibility::template DERIVES_FROM_BASE<Derived>,
255 "Derived is not a derived class of Base.");
256 static_assert(
257 Compatibility::template HAS_ALIGNMENT<Derived>,
258 "The derived type has incompatible alignment.");
259
260 ::new (static_cast<void *>(_storage)) _Holder<Derived>(
261 std::forward<Args>(args)...);
262}
263
264template <class Base, size_t BufferSize>
265template <class Derived>
266bool
268 HasBaseAtSameAddress(const Derived &derived)
269{
270 if constexpr (!DERIVES_FROM_BASE<Derived>) {
271 return false;
272 }
273
274 const Base *base = static_cast<const Base *>(&derived);
275 const void *baseAddress = static_cast<const void *>(base);
276 const void *derivedAddress = static_cast<const void *>(&derived);
277 return baseAddress == derivedAddress;
278}
279
280PXR_NAMESPACE_CLOSE_SCOPE
281
282#endif
Enables a base class to be used with EsfFixedSizePolymorphicHolder.
Stores polymorphic objects in a fixed-size buffer.
This & operator=(const This &other)
Construct a new instance that is copy-constructed from the instance in another holder.
EsfFixedSizePolymorphicHolder(const This &other)
Construct a holder containing a derived type instance that is copy- constructed from another holder.
This & operator=(This &&other)
Construct a new instance that is move-constructed from the instance in another holder.
EsfFixedSizePolymorphicHolder(This &&other)
Construct a holder containing a derived type that is move-constructed from another holder.
EsfFixedSizePolymorphicHolder()=delete
The default constructor is deleted because instances must always contain a derived object.
~EsfFixedSizePolymorphicHolder()
Destroys the derived instance held by this object.
Stripped down version of diagnostic.h that doesn't define std::string.
#define TF_AXIOM(cond)
Aborts if the condition cond is not met.
Definition: diagnostic.h:193
#define TF_UNUSED(x)
Stops compiler from producing unused argument or variable warnings.
Definition: tf.h:168
STL namespace.
Checks if instances of Derived can be stored in this holder.
static bool HasBaseAtSameAddress(const Derived &derived)
Verifies that a Derived instance has the same address as its Base.
A file containing basic constants and definitions.