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