XRTraits C++ OpenXR Utilities
InitXrType.h
Go to the documentation of this file.
1 // Copyright 2018-2019, Collabora, Ltd.
2 // SPDX-License-Identifier: BSL-1.0
3 /*!
4  * @file
5  * @brief Header providing a variety of ways to create or initialize an OpenXR
6  * "tagged struct".
7  * @author Ryan Pavlik <ryan.pavlik@collabora.com>
8  */
9 
10 #pragma once
11 
12 // Internal Includes
13 #include "DynamicVerified.h"
14 #include "traits/APITraits.h"
15 
16 // Library Includes
17 #include <openxr/openxr.h>
18 
19 // Standard Includes
20 #include <cstring>
21 #include <type_traits>
22 #include <vector>
23 
24 namespace xrtraits {
25 
26 /*!
27  * @defgroup Initialization Initializing OpenXR Structs
28  *
29  * @brief Wrapper types and functions to build known-good OpenXR structs.
30  */
31 
32 /*! Given a pointer to some storage to use as an OpenXR tagged type, zeros the
33  * storage and sets the type member.
34  *
35  * Overload that automatically deduces the type from the passed pointer.
36  *
37  * @ingroup Initialization
38  */
39 template <typename T> inline T* initXrType(T* storage)
40 {
41  static_assert(traits::has_xr_type_tag_v<T>,
42  "Can only call initXrType to initialize a type with a "
43  "known OpenXR type tag");
44  static_assert(
45  !is_const_v<T>,
46  "Doesn't make sense to pass a reference to const to initXrType()");
47  std::memset(storage, 0, sizeof(T));
48  storage->type = traits::xr_type_tag_v<T>;
49  return storage;
50 }
51 
52 /*! Given an OpenXR tagged type and a pointer to sufficient storage, zeros the
53  * storage and sets the type member.
54  *
55  * @ingroup Initialization
56  */
57 template <typename T> inline T* initXrType(void* storage)
58 {
59  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
60  return initXrType(reinterpret_cast<T*>(storage));
61 }
62 
63 /*! Given a reference to some storage to use as an OpenXR tagged type, zeros the
64  * storage and sets the type member.
65  *
66  * Overload that automatically deduces the type from the passed reference.
67  *
68  * @ingroup Initialization
69  */
70 template <typename T> inline T* initXrType(T& storage)
71 {
72  static_assert(
73  !is_const_v<T>,
74  "Doesn't make sense to pass a reference to const to initXrType()");
75  return initXrType(&storage);
76 }
77 
78 #ifndef XRTRAITS_DOXYGEN
79 
80 namespace detail {
81  //! Wraps initXrType() to avoid needing constexpr-if
82  template <typename T, typename = void> struct ConditionalInitXrType
83  {
84  static void apply(T&) {}
85  };
86  template <typename T>
87  struct ConditionalInitXrType<
88  T, std::enable_if_t<traits::has_xr_type_tag_v<T>>>
89  {
90  static void apply(T& storage) { initXrType(&storage); }
91  };
92 } // namespace detail
93 
94 #endif // !XRTRAITS_DOXYGEN
95 
96 /*! Creates, initializes, and returns an instance of an OpenXR tagged type.
97  *
98  * Sets the type member and zeros the rest of the storage.
99  *
100  * @ingroup Initialization
101  */
102 template <typename T> inline T make_zeroed()
103 {
104  T ret{};
105  detail::ConditionalInitXrType<T>::apply(ret);
106  return ret;
107 }
108 
109 /*! Creates, initializes, and returns a vector containing the given number of
110  * empty instances of an OpenXR tagged type.
111  *
112  * @ingroup Initialization
113  */
114 template <typename T> inline std::vector<T> make_zeroed_vector(size_t n)
115 {
116  return std::vector<T>{n, make_zeroed<T>()};
117 }
118 
119 #ifndef XRTRAITS_DOXYGEN
120 template <typename T> struct Initialized;
121 namespace detail {
122  template <typename T>
123  struct is_chainable_struct_oracle : std::false_type
124  {
125  };
126 #ifdef XRTRAITS_HAVE_DYNAMIC_VERIFIED
127  template <typename U>
128  struct is_chainable_struct_oracle<DynamicVerified<U>> : std::true_type
129  {
130  };
131 #endif // XRTRAITS_HAVE_DYNAMIC_VERIFIED
132 
133  template <typename U>
134  struct is_chainable_struct_oracle<Initialized<U>> : std::true_type
135  {
136  };
137  template <typename T>
138  constexpr bool is_chainable_struct_v = is_chainable_struct_oracle<
139  std::remove_cv_t<std::remove_reference_t<T>>>::value;
140 } // namespace detail
141 #endif // !XRTRAITS_DOXYGEN
142 
143 #if defined(__GCC__)
144 // This warning will trigger for most uses of Initialized, because we're
145 // (intentionally, in most cases) only providing initializers for the type and
146 // next.
147 #pragma GCC diagnostic push
148 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
149 #endif
150 
151 /*! Wrapper for stack-allocated OpenXR tagged structs that auto-initializes the
152  * type member correctly.
153  *
154  * Inherits from the type parameter, so this object is the same size as the
155  * OpenXR struct and exposes the same members, etc...
156  *
157  * @tparam T an OpenXR tagged type with known type tag.
158  *
159  * @ingroup Initialization
160  */
161 template <typename T> struct Initialized : T
162 {
163  static_assert(traits::has_xr_type_tag_v<T>,
164  "Can only use Initialized<T> with a type with a known "
165  "OpenXR type tag");
166  static_assert(!is_pointer_v<T>,
167  "Can't use Initialized<T> with a pointer type - just use "
168  "the bare type, we are stack allocating.");
169  static_assert(!is_reference_v<T>,
170  "Can't use Initialized<T> with a reference type.");
171  static_assert(!is_const_v<T>,
172  "Can't use Initialized<T> with a const type - doesn't "
173  "make any sense.");
174 
175  //! The OpenXR structure type.
176  using xr_type = T;
177 
178  //! The OpenXR structure type (const).
179  using const_xr_type = std::add_const_t<T>;
180 
181  //! Get pointer to OpenXR type.
182  constexpr xr_type* get() noexcept { return this; }
183 
184  //! Get pointer to OpenXR type (const overload).
185  constexpr const_xr_type* get() const noexcept { return this; }
186 
187  /*! Can't access the underlying struct's type member by design.
188  *
189  * Naming this here and explicitly deleting it makes it harder to
190  * accidentally mess up an OpenXR struct's `type` member (unless you
191  * really try hard). If you get an error on this line, it's because
192  * you're trying to manually look at or modify type, which shouldn't be
193  * done.
194  */
195  void type() const = delete;
196 
197  /*! Can't access the underlying struct's next member by design.
198  *
199  * Naming this here and explicitly deleting it makes it harder to
200  * accidentally mess up an OpenXR struct's `next` member (unless you
201  * really try hard). If you get an error on this line, it's because
202  * you're trying to manually look at or modify type, which shouldn't be
203  * done.
204  */
205  void next() const = delete;
206 
207  //! Default constructor - initializes OpenXR struct's type member.
208  constexpr Initialized() noexcept : T({})
209  {
210  // Not using initializer because that would produce "missing
211  // initializer for member" warnings.
212  static_cast<T*>(this)->type = traits::xr_type_tag_v<T>;
213  }
214 
215 #ifdef XRTRAITS_HAVE_DYNAMIC_VERIFIED
216  /*! Constructor to reference a chained struct (passed as
217  * DynamicVerified<U>).
218  *
219  * Initializes OpenXR struct's type member, and the
220  * next member to the given structure's address. Any additional
221  * parameters are forwarded as member initializers to the underlying
222  * struct.
223  */
224  template <typename U, typename... Args>
225  explicit constexpr Initialized(
226  DynamicVerified<U> nextStruct,
227  Args... a) noexcept(noexcept(nextStruct.get()))
228  : T({traits::xr_type_tag_v<T>, nextStruct.get(),
229  std::forward<Args>(a)...})
230  {}
231 #endif // XRTRAITS_HAVE_DYNAMIC_VERIFIED
232 
233  /*! Constructor to reference a chained struct (passed as
234  * Initialized<U>).
235  *
236  * Initializes OpenXR struct's type member, and the
237  * next member to the given structure's address. Any additional
238  * parameters are forwarded as member initializers to the underlying
239  * struct.
240  */
241  template <typename U, typename... Args>
242  explicit constexpr Initialized(Initialized<U> const& nextStruct,
243  Args... a) noexcept
244  : T({traits::xr_type_tag_v<T>, nextStruct.get(),
245  std::forward<Args>(a)...})
246  {
247  static_assert(
248  sizeof...(a) != 0 ||
249  !is_same_v<std::remove_cv_t<T>, std::remove_cv_t<U>>,
250  "Can't copy Initialized<T> structures.");
251  }
252 
253  /*! Constructor to reference a possibly non-const chained struct (passed
254  * as Initialized<U>).
255  *
256  * Initializes OpenXR struct's type member, and the
257  * next member to the given structure's address. Any additional
258  * parameters are forwarded as member initializers to the underlying
259  * struct.
260  */
261  template <typename U, typename... Args>
262  explicit constexpr Initialized(Initialized<U>& nextStruct,
263  Args... a) noexcept
264  : T({traits::xr_type_tag_v<T>, nextStruct.get(),
265  std::forward<Args>(a)...})
266  {
267  static_assert(
268  !is_same_v<std::remove_cv_t<T>, std::remove_cv_t<U>>,
269  "Can't copy Initialized<T> "
270  "structures.");
271  }
272  /*! Constructor that forwards initializers and has no chained struct.
273  *
274  * Initializes OpenXR struct's type member, and forwards the rest of the
275  * arguments on as initializers.
276  */
277  template <
278  typename A1, typename... Args,
279  typename = std::enable_if_t<!detail::is_chainable_struct_v<A1>>>
280  explicit constexpr Initialized(A1&& a1, Args... a) noexcept
281  : T({traits::xr_type_tag_v<T>, nullptr, std::forward<A1>(a1),
282  std::forward<Args>(a)...})
283  {}
284 
285  /*! Default move-constructor - mainly for assignment-style
286  * initialization.
287  */
288  constexpr Initialized(Initialized&&) noexcept = default;
289 
290  // Non-copy-constructible
291  constexpr Initialized(Initialized const&) = delete;
292  // Non-copy-assignable
293  constexpr Initialized& operator=(Initialized const&) = delete;
294  // Non-move-assignable
295  constexpr Initialized& operator=(Initialized&&) = delete;
296 
297  // Default destructor
298  ~Initialized() = default;
299 
300 #ifdef XRTRAITS_HAVE_DYNAMIC_VERIFIED
301  //! The DynamicVerified class associated with this type as non-const.
302  using verified_type = DynamicVerified<xr_type>;
303 
304  //! The DynamicVerified class associated with this type as const.
305  using const_verified_type = DynamicVerified<std::add_const_t<xr_type>>;
306 
307  /*! Manual conversion to DynamicVerified<T>.
308  *
309  * By design, this class ensures the dynamic type is correct, so we get
310  * to skip verification and use the private constructor.
311  */
312  constexpr verified_type asVerified() { return verified_type{*get()}; }
313 
314  /*! Manual conversion to DynamicVerified<const T> (const overload).
315  *
316  * By design, this class ensures the dynamic type is correct, so we get
317  * to skip verification and use the private constructor.
318  */
319  constexpr const_verified_type asVerified() const
320  {
321  return const_verified_type{*get()};
322  }
323 
324  /*! Manual conversion to DynamicVerified<const T>.
325  *
326  * By design, this class ensures the dynamic type is correct, so we get
327  * to skip verification and use the private constructor.
328  */
329  constexpr const_verified_type asVerifiedConst() const
330  {
331  return asVerified();
332  }
333 
334  /*! Conversion operator to DynamicVerified<T>.
335  *
336  * By design, this class ensures the dynamic type is correct, so we get
337  * to skip verification and use the private constructor.
338  */
339  constexpr operator verified_type() { return asVerified(); }
340 
341  /*! Conversion operator to DynamicVerified<const T>.
342  *
343  * By design, this class ensures the dynamic type is correct, so we get
344  * to skip verification and use the private constructor.
345  */
346  constexpr operator const_verified_type() const { return asVerified(); }
347 #endif // XRTRAITS_HAVE_DYNAMIC_VERIFIED
348 };
349 
350 #if defined(__GCC__)
351 #pragma GCC diagnostic pop
352 #endif
353 
354 } // namespace xrtraits
Main namespace for these C++ OpenXR utilities.
Definition: GetChained.h:26
T xr_type
The OpenXR structure type.
Definition: InitXrType.h:176
C++ type traits related to OpenXR, and some other compile-time functionality.
constexpr bool is_same_v
Variable template wrapping std::is_same<T, U>::value.
Definition: Common.h:34
T * initXrType(T *storage)
Definition: InitXrType.h:39
constexpr Initialized(Initialized< U > const &nextStruct, Args... a) noexcept
Definition: InitXrType.h:242
constexpr Initialized(A1 &&a1, Args... a) noexcept
Definition: InitXrType.h:280
Definition: InitXrType.h:161
T make_zeroed()
Definition: InitXrType.h:102
std::vector< T > make_zeroed_vector(size_t n)
Definition: InitXrType.h:114
constexpr Initialized(Initialized< U > &nextStruct, Args... a) noexcept
Definition: InitXrType.h:262
std::add_const_t< T > const_xr_type
The OpenXR structure type (const).
Definition: InitXrType.h:179
Header providing type-enforced verification of OpenXR "tagged types".
constexpr Initialized() noexcept
Default constructor - initializes OpenXR struct&#39;s type member.
Definition: InitXrType.h:208