XRTraits C++ OpenXR Utilities
TaggedDynamicCast.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 dynamic_cast equivalent for OpenXR tagged types,
6  * xr_tagged_dynamic_cast().
7  * @author Ryan Pavlik <ryan.pavlik@collabora.com>
8  */
9 
10 #pragma once
11 
12 #include "../Common.h"
13 
14 #ifdef XRTRAITS_HAVE_CONSTEXPR_IF
15 
16 // Internal Includes
17 #include "../Attributes.h"
18 #include "../exceptions/CastExceptions.h"
19 #include "TaggedCastCommon.h"
20 
21 // Library Includes
22 // - none
23 
24 // Standard Includes
25 // - none
26 
27 namespace xrtraits {
28 
29 namespace casts {
30 
31  /*! OpenXR structure cast, analogous to the standard
32  * dynamic_cast.
33  *
34  * Provide a single type parameter (target type) as well as the
35  * pointer/reference parameter.
36  *
37  * Input should be a pointer or reference to a (possibly const)
38  * structure, with static type starting with `XrStructureType
39  * type; const void * next;`. The `type` member of the input is
40  * examined to ensure it matches the value defined by the spec
41  * (as indicated by generated type traits) for the TargetType
42  * provided.
43  *
44  * - If TargetType is a pointer type, then a mismatch of `type`
45  * (or input of nullptr) results in a nullptr return.
46  * - If TargetType is a reference type, then a mismatch of
47  * `type` (or input of nullptr) results in a bad_tagged_cast
48  * exception.
49  *
50  * @ingroup Casts
51  */
52  template <typename TargetType, typename SourceType>
53  inline TargetType xr_tagged_dynamic_cast(SourceType&& source)
54  {
55  using std::conditional_t;
56  using std::remove_reference_t;
57  using Src =
58  conditional_t<is_pointer_v<remove_reference_t<SourceType>>,
59  remove_reference_t<SourceType>, SourceType>;
60  using Tgt = TargetType;
61  // This cast operation requires knowing that the
62  // parameter type is an XR tagged type: it doesn't just
63  // take your word for it like xr_tagged_risky_cast does.
64  static_assert(
65  traits::is_xr_tagged_type_v<Src>,
66  "Can only use xr_tagged_dynamic_cast to cast from "
67  "a pointer/reference to (possibly const) XR tagged "
68  "types. If you really want to cast from something like a "
69  "void *, you are looking for xr_tagged_risky_cast.");
70 
71  static_assert(
72  traits::is_xr_tagged_type_v<Tgt>,
73  "Can only use xr_tagged_dynamic_cast to cast to a "
74  "pointer/reference to a (possibly const) XR tagged "
75  "type.");
76 
77  // Cast determines whether to perform reinterpret or
78  // return nullptr based on comparing value of `type` to
79  // expected value for the target type, so there must
80  // actually be such an expected value. (Note that we
81  // don't require this for the source type: there we only
82  // care that the member exists, so we can compare it to
83  // the value we're verifying the existence of here.)
84  static_assert(
85  traits::has_xr_type_tag_v<Tgt>,
86  "Can only use xr_tagged_dynamic_cast to cast to a "
87  "pointer/reference to a concrete XR tagged type "
88  "with a known, defined type tag value (XrStructureType "
89  "enum value).");
90 
91  static_assert(detail::points_or_refers_to_const_v<Src>
92  ? detail::points_or_refers_to_const_v<Tgt>
93  : true,
94  "Cannot remove const qualification through "
95  "xr_tagged_dynamic_cast");
96 #ifndef XRTRAITS_USE_EXCEPTIONS
97  static_assert(is_pointer_v<Tgt>,
98  "Casts to references require the availability of "
99  "xrtraits exceptions.");
100 #endif // !XRTRAITS_USE_EXCEPTIONS
101 
102  XRTRAITS_MAYBE_UNUSED static const char castType[] =
103  "xr_tagged_dynamic_cast";
104  constexpr bool is_target_pointer = is_pointer_v<Tgt>;
105 
106  if constexpr (is_pointer_v<Src>) {
107  // Pointer input: must check for nullptr.
108 
109  if (source == nullptr) {
110  if constexpr (is_target_pointer) {
111  // nullptr in, return nullptr
112  return nullptr;
113  } else { // NOLINT(readability-else-after-return)
114 
115  // nullptr in, exception
116 #ifdef XRTRAITS_USE_EXCEPTIONS
118  traits::xr_type_tag_v<Tgt>, nullptr,
119  castType);
120 #endif // XRTRAITS_USE_EXCEPTIONS
121  }
122  }
123  }
124 
125  if (traits::xr_type_tag_v<Tgt> == detail::get_type(source)) {
126  // matching type tag in: do the casting and
127  // address-taking/dereferencing
128  return detail::perform_dereferencing_reinterpret_cast<
129  Tgt>(source);
130  }
131 
132  // tag on type didn't match what was expected
133  if constexpr (is_target_pointer) {
134  // tag mismatch, return nullptr
135  return nullptr;
136  } else { // NOLINT(readability-else-after-return)
137 
138  // tag mismatch, throw exception
139 #ifdef XRTRAITS_USE_EXCEPTIONS
141  traits::xr_type_tag_v<Tgt>,
142  detail::get_type(source), castType);
143 #endif // XRTRAITS_USE_EXCEPTIONS
144  }
145  }
146 
147 } // namespace casts
148 
149 } // namespace xrtraits
150 
151 #endif // XRTRAITS_HAVE_CONSTEXPR_IF
Main namespace for these C++ OpenXR utilities.
Definition: GetChained.h:26
#define XRTRAITS_MAYBE_UNUSED
Compatibility wrapper for [[maybe_unused]]
Definition: Attributes.h:26
Definition: CastExceptions.h:38
TargetType xr_tagged_dynamic_cast(SourceType &&source)
Definition: TaggedDynamicCast.h:53
Header shared between the two type-safe cast headers.