HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ImathTypeTraits.h
Go to the documentation of this file.
1 //
2 // SPDX-License-Identifier: BSD-3-Clause
3 // Copyright Contributors to the OpenEXR Project.
4 //
5 
6 //
7 // This file contains type traits related to or used by the Imath library.
8 //
9 
10 #ifndef INCLUDED_IMATHTYPETRAITS_H
11 #define INCLUDED_IMATHTYPETRAITS_H
12 
13 #include <type_traits>
14 
15 #include "ImathPlatform.h"
16 
17 IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
18 
19 /// Define Imath::enable_if_t to be std for C++14, equivalent for C++11.
20 #if (IMATH_CPLUSPLUS_VERSION >= 14)
21 using std::enable_if_t; // Use C++14 std::enable_if_t
22 #else
23 // Define enable_if_t for C++11
24 template <bool B, class T = void>
26 #endif
27 
28 /// An enable_if helper to be used in template parameters which results in
29 /// much shorter symbols.
30 #define IMATH_ENABLE_IF(...) \
31  IMATH_INTERNAL_NAMESPACE::enable_if_t<(__VA_ARGS__), int> = 0
32 
33 #if IMATH_FOREIGN_VECTOR_INTEROP
34 
35 /// @{
36 /// @name Detecting interoperable types.
37 ///
38 /// In order to construct or assign from external "compatible" types without
39 /// prior knowledge of their definitions, we have a few helper type traits.
40 /// The intent of these is to allow custom linear algebra types in an
41 /// application that have seamless conversion to and from Imath types.
42 ///
43 /// `has_xy<T,Base>`, `has_xyz<T,Base>`, `has_xyzw<T,Base>` detect if class
44 /// `T` has elements `.x`, `.y`, and `.z` all of type `Base` and seems to be
45 /// the right size to hold exactly those members and nothing more.
46 ///
47 /// `has_subscript<T,Base,N>` detects if class `T` can perform `T[int]`
48 /// to yield a `Base`, and that it seems to be exactly the right size to
49 /// hold `N` of those elements.
50 ///
51 /// This is not exact. It's possible that for a particular user-defined
52 /// type, this may yield a false negative or false positive. For example:
53 /// * A class for a 3-vector that contains an extra element of padding
54 /// so that it will have the right size and alignment to use 4-wide
55 /// SIMD math ops will appear to be the wrong size.
56 /// * A `std::vector<T>` is subscriptable and might have N elements at
57 /// runtime, but the size is dynamic and so would fail this test.
58 /// * A foreign type may have .x, .y, .z that are not matching our base
59 /// type but we still want it to work (with appropriate conversions).
60 ///
61 /// In these cases, user code may declare an exception -- for example,
62 /// stating that `mytype` should be considered implicitly convertible to
63 /// an Imath::V3f by subscripting:
64 ///
65 /// template<>
66 /// struct Imath::has_subscript<mytype, float, 3> : public std::true_type { };
67 ///
68 /// And similarly, user code may correct a potential false positive (that
69 /// is, a `mytype` looks like it should be convertible to a V3f, but you
70 /// don't want it to ever happen):
71 ///
72 /// template<typename B, int N>
73 /// struct Imath::has_subscript<mytype, B, N> : public std::false_type { };
74 ///
75 
76 /// `has_xy<T,Base>::value` will be true if type `T` has member variables
77 /// `.x` and `.y`, all of type `Base`, and the size of a `T` is exactly big
78 /// enough to hold 2 Base values.
79 template <typename T, typename Base> struct has_xy
80 {
81 private:
82  typedef char Yes[1];
83  typedef char No[2];
84 
85  // Valid only if .x, .y exist and are the right type: return a Yes.
86  template <
87  typename C,
88  IMATH_ENABLE_IF (std::is_same<decltype (C {}.x), Base>::value),
89  IMATH_ENABLE_IF (std::is_same<decltype (C {}.y), Base>::value)>
90  static Yes& test (int);
91 
92  // Fallback, default to returning a No.
93  template <typename C> static No& test (...);
94 
95 public:
96  enum
97  {
98  value =
99  (sizeof (test<T> (0)) == sizeof (Yes) &&
100  sizeof (T) == 2 * sizeof (Base))
101  };
102 };
103 
104 /// `has_xyz<T,Base>::value` will be true if type `T` has member variables
105 /// `.x`, `.y`, and `.z`, all of type `Base`, and the size of a `T` is
106 /// exactly big enough to hold 3 Base values.
107 template <typename T, typename Base> struct has_xyz
108 {
109 private:
110  typedef char Yes[1];
111  typedef char No[2];
112 
113  // Valid only if .x, .y, .z exist and are the right type: return a Yes.
114  template <
115  typename C,
116  IMATH_ENABLE_IF (std::is_same<decltype (C {}.x), Base>::value),
117  IMATH_ENABLE_IF (std::is_same<decltype (C {}.y), Base>::value),
118  IMATH_ENABLE_IF (std::is_same<decltype (C {}.z), Base>::value)>
119  static Yes& test (int);
120 
121  // Fallback, default to returning a No.
122  template <typename C> static No& test (...);
123 
124 public:
125  enum
126  {
127  value =
128  (sizeof (test<T> (0)) == sizeof (Yes) &&
129  sizeof (T) == 3 * sizeof (Base))
130  };
131 };
132 
133 /// `has_xyzw<T,Base>::value` will be true if type `T` has member variables
134 /// `.x`, `.y`, `.z`, and `.w`, all of type `Base`, and the size of a `T` is
135 /// exactly big enough to hold 4 Base values.
136 template <typename T, typename Base> struct has_xyzw
137 {
138 private:
139  typedef char Yes[1];
140  typedef char No[2];
141 
142  // Valid only if .x, .y, .z, .w exist and are the right type: return a Yes.
143  template <
144  typename C,
145  IMATH_ENABLE_IF (std::is_same<decltype (C {}.x), Base>::value),
146  IMATH_ENABLE_IF (std::is_same<decltype (C {}.y), Base>::value),
147  IMATH_ENABLE_IF (std::is_same<decltype (C {}.z), Base>::value),
148  IMATH_ENABLE_IF (std::is_same<decltype (C {}.w), Base>::value)>
149  static Yes& test (int);
150 
151  // Fallback, default to returning a No.
152  template <typename C> static No& test (...);
153 
154 public:
155  enum
156  {
157  value =
158  (sizeof (test<T> (0)) == sizeof (Yes) &&
159  sizeof (T) == 4 * sizeof (Base))
160  };
161 };
162 
163 /// `has_subscript<T,Base,Nelem>::value` will be true if type `T` has
164 /// subscripting syntax, a `T[int]` returns a `Base`, and the size of a `T`
165 /// is exactly big enough to hold `Nelem` `Base` values.
166 template <typename T, typename Base, int Nelem> struct has_subscript
167 {
168 private:
169  typedef char Yes[1];
170  typedef char No[2];
171 
172  // Valid only if T[] is possible and is the right type: return a Yes.
173  template <
174  typename C,
175  IMATH_ENABLE_IF (std::is_same<
176  typename std::decay<decltype (C {}[0])>::type,
177  Base>::value)>
178  static Yes& test (int);
179 
180  // Fallback, default to returning a No.
181  template <typename C> static No& test (...);
182 
183 public:
184  enum
185  {
186  value =
187  (sizeof (test<T> (0)) == sizeof (Yes) &&
188  sizeof (T) == Nelem * sizeof (Base))
189  };
190 };
191 
192 /// C arrays of just the right length also are qualified for has_subscript.
193 template <typename Base, int Nelem>
194 struct has_subscript<Base[Nelem], Base, Nelem> : public std::true_type
195 {};
196 
197 /// `has_double_subscript<T,Base,Rows,Cols>::value` will be true if type `T`
198 /// has 2-level subscripting syntax, a `T[int][int]` returns a `Base`, and
199 /// the size of a `T` is exactly big enough to hold `R*C` `Base` values.
200 template <typename T, typename Base, int Rows, int Cols>
201 struct has_double_subscript
202 {
203 private:
204  typedef char Yes[1];
205  typedef char No[2];
206 
207  // Valid only if T[][] is possible and is the right type: return a Yes.
208  template <
209  typename C,
210  IMATH_ENABLE_IF (std::is_same<
211  typename std::decay<decltype (C {}[0][0])>::type,
212  Base>::value)>
213  static Yes& test (int);
214 
215  // Fallback, default to returning a No.
216  template <typename C> static No& test (...);
217 
218 public:
219  enum
220  {
221  value =
222  (sizeof (test<T> (0)) == sizeof (Yes) &&
223  sizeof (T) == (Rows * Cols) * sizeof (Base))
224  };
225 };
226 
227 /// C arrays of just the right length also are qualified for has_double_subscript.
228 template <typename Base, int Rows, int Cols>
229 struct has_double_subscript<Base[Rows][Cols], Base, Rows, Cols>
230  : public std::true_type
231 {};
232 
233 /// @}
234 
235 #endif
236 
237 IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
238 
239 #endif // INCLUDED_IMATHTYPETRAITS_H
type
Definition: core.h:556
typename std::enable_if< B, T >::type enable_if_t
Define Imath::enable_if_t to be std for C++14, equivalent for C++11.
cvex test(vector P=0;int unbound=3;export float s=0;export vector Cf=0;)
Definition: test.vfl:11
GLsizei const GLfloat * value
Definition: glcorearb.h:824
has_subscript<T>::value is true if T has a subscript operator.
Definition: type_traits.h:54
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
#define IMATH_ENABLE_IF(...)