HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
vecparam.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenImageIO project.
2 // SPDX-License-Identifier: Apache-2.0
3 // https://github.com/AcademySoftwareFoundation/OpenImageIO
4 
5 #pragma once
6 #define OIIO_VECPARAM_H 1
7 
8 #include <algorithm>
9 #include <cstring>
10 
11 #include <OpenImageIO/platform.h>
12 
13 
15 
16 // NOTE: These interoperable type templates were copied from the
17 // [Imath project](http://github.com/AcademySoftwareFoundation/imath),
18 // licensed under the same BSD-3-clause license as OpenImageIO.
19 
20 
21 /// @{
22 /// @name Detecting interoperable linear algebra types.
23 ///
24 /// In order to construct or assign from external "compatible" types without
25 /// prior knowledge of their definitions, we have a few helper type traits.
26 /// The intent of these is to allow custom linear algebra types in an
27 /// application that have seamless conversion to and from similar types.
28 ///
29 /// `has_xy<T,Base>`, `has_xyz<T,Base>`, `has_xyzw<T,Base>` detect if class
30 /// `T` has the right set of elements `.x`, `.y`, `.z`, `.w`, all of type
31 /// `Base` and seems to be the right size to hold exactly those members and
32 /// nothing more.
33 ///
34 /// `has_subscript_N<T,Base,Nelem>` detects if class `T` can perform `T[int]`
35 /// to yield a `Base`, and that it seems to be exactly the right size to
36 /// hold `Nelem` of those elements.
37 ///
38 /// This is not exact. It's possible that for a particular user-defined
39 /// type, this may yield a false negative or false positive. For example:
40 /// * A class for a 3-vector that contains an extra element of padding
41 /// so that it will have the right size and alignment to use 4-wide
42 /// SIMD math ops will appear to be the wrong size.
43 /// * A `std::vector<T>` is subscriptable and might have N elements at
44 /// runtime, but the size is dynamic and so would fail this test.
45 /// * A foreign type may have .x, .y, .z that are not matching our base
46 /// type but we still want it to work (with appropriate conversions).
47 ///
48 /// In these cases, user code may declare an exception -- for example,
49 /// stating that `mytype` should be considered a subscriptable 3-vector:
50 ///
51 /// template<>
52 /// struct OIIO::has_subscript_N<mytype, float, 3> : public std::true_type { };
53 ///
54 /// And similarly, user code may correct a potential false positive (that
55 /// is, a `mytype` looks like it should be a 3-vector, but we don't want any
56 /// implicit conversions to happen):
57 ///
58 /// template<typename B, int N>
59 /// struct OIIO::has_subscript_N<mytype, B, N> : public std::false_type { };
60 ///
61 
62 
63 /// `has_xy<T,Base>::value` will be true if type `T` has member variables
64 /// `.x` and `.y`, all of type `Base`, and the size of a `T` is exactly big
65 /// enough to hold 2 Base values.
66 template<typename T, typename Base> struct has_xy {
67 private:
68  typedef char Yes[1];
69  typedef char No[2];
70 
71  // Valid only if .x, .y exist and are the right type: return a Yes.
72  template<typename C,
73  OIIO_ENABLE_IF(std::is_same<decltype(C().x), Base>::value),
74  OIIO_ENABLE_IF(std::is_same<decltype(C().y), Base>::value)>
75  static Yes& test(int);
76 
77  // Fallback, default to returning a No.
78  template<typename C> static No& test(...);
79 
80 public:
81  enum {
82  value = (sizeof(test<T>(0)) == sizeof(Yes)
83  && sizeof(T) == 2 * sizeof(Base))
84  };
85 };
86 
87 
88 /// `has_xyz<T,Base>::value` will be true if type `T` has member variables
89 /// `.x`, `.y`, and `.z`, all of type `Base`, and the size of a `T` is
90 /// exactly big enough to hold 3 Base values.
91 template<typename T, typename Base> struct has_xyz {
92 private:
93  typedef char Yes[1];
94  typedef char No[2];
95 
96  // Valid only if .x, .y, .z exist and are the right type: return a Yes.
97  template<typename C,
98  OIIO_ENABLE_IF(std::is_same<decltype(C().x), Base>::value),
99  OIIO_ENABLE_IF(std::is_same<decltype(C().y), Base>::value),
100  OIIO_ENABLE_IF(std::is_same<decltype(C().z), Base>::value)>
101  static Yes& test(int);
102 
103  // Fallback, default to returning a No.
104  template<typename C> static No& test(...);
105 
106 public:
107  enum {
108  value = (sizeof(test<T>(0)) == sizeof(Yes)
109  && sizeof(T) == 3 * sizeof(Base))
110  };
111 };
112 
113 
114 /// `has_xyzw<T,Base>::value` will be true if type `T` has member variables
115 /// `.x`, `.y`, `.z`, and `.w`, all of type `Base`, and the size of a `T` is
116 /// exactly big enough to hold 4 Base values.
117 template<typename T, typename Base> struct has_xyzw {
118 private:
119  typedef char Yes[1];
120  typedef char No[2];
121 
122  // Valid only if .x, .y, .z, .w exist and are the right type: return a Yes.
123  template<typename C,
124  OIIO_ENABLE_IF(std::is_same<decltype(C().x), Base>::value),
125  OIIO_ENABLE_IF(std::is_same<decltype(C().y), Base>::value),
126  OIIO_ENABLE_IF(std::is_same<decltype(C().z), Base>::value),
127  OIIO_ENABLE_IF(std::is_same<decltype(C().w), Base>::value)>
128  static Yes& test(int);
129 
130  // Fallback, default to returning a No.
131  template<typename C> static No& test(...);
132 
133 public:
134  enum {
135  value = (sizeof(test<T>(0)) == sizeof(Yes)
136  && sizeof(T) == 4 * sizeof(Base))
137  };
138 };
139 
140 
141 
142 /// `has_subscript_N<T,Base,Nelem>::value` will be true if type `T` has
143 /// subscripting syntax, a `T[int]` returns a `Base`, and the size of a `T`
144 /// is exactly big enough to hold `Nelem` `Base` values.
145 template<typename T, typename Base, int Nelem> struct has_subscript_N {
146 private:
147  typedef char Yes[1];
148  typedef char No[2];
149 
150  // Valid only if T[] is possible and is the right type: return a Yes.
151  template<
152  typename C,
153  OIIO_ENABLE_IF(std::is_same<typename std::decay<decltype(C()[0])>::type,
154  Base>::value)>
155  static Yes& test(int);
156 
157  // Fallback, default to returning a No.
158  template<typename C> static No& test(...);
159 
160 public:
161  enum {
162  value = (sizeof(test<T>(0)) == sizeof(Yes)
163  && sizeof(T) == Nelem * sizeof(Base))
164  };
165 };
166 
167 
168 
169 /// C arrays of just the right length also are qualified for has_subscript_N.
170 template<typename Base, int Nelem>
171 struct has_subscript_N<Base[Nelem], Base, Nelem> : public std::true_type {};
172 
173 
174 
175 /// `has_double_subscript_RC<T,Base,Rows,Cols>::value` will be true if type `T`
176 /// has 2-level subscripting syntax, a `T[int][int]` returns a `Base`, and
177 /// the size of a `T` is exactly big enough to hold `R*C` `Base` values.
178 template<typename T, typename Base, int Rows, int Cols>
180 private:
181  typedef char Yes[1];
182  typedef char No[2];
183 
184  // Valid only if T[][] is possible and is the right type: return a Yes.
185  template<typename C,
187  std::is_same<typename std::decay<decltype(C()[0][0])>::type,
188  Base>::value)>
189  static Yes& test(int);
190 
191  // Fallback, default to returning a No.
192  template<typename C> static No& test(...);
193 
194 public:
195  enum {
196  value = (sizeof(test<T>(0)) == sizeof(Yes)
197  && sizeof(T) == (Rows * Cols) * sizeof(Base))
198  };
199 };
200 
201 
202 /// C arrays of just the right length also are qualified for has_double_subscript_RC.
203 template<typename Base, int Rows, int Cols>
204 struct has_double_subscript_RC<Base[Rows][Cols], Base, Rows, Cols>
205  : public std::true_type {};
206 
207 /// @}
208 
209 
210 
211 /// Vec3Param<T> is a helper class that lets us create an interface that takes
212 /// a proxy for a `T[3]` analogue for use as a public API function parameter
213 /// type, in order to not expose the underlying vector type.
214 ///
215 /// For example, suppose we have a public function like this:
216 ///
217 /// void foo(Vec3Param<float> v);
218 ///
219 /// Then any of the following calls will work:
220 ///
221 /// float array[3];
222 /// foo(array);
223 ///
224 /// foo(Imath::V3f(1,2,3));
225 ///
226 template<typename T> class Vec3Param {
227 public:
228  /// Construct directly from 3 floats.
229  OIIO_HOSTDEVICE constexpr Vec3Param(T x, T y, T z) noexcept
230  : x(x)
231  , y(y)
232  , z(z)
233  {
234  }
235 
236  /// Construct from anything that looks like a 3-vector, having .x, .y, and
237  /// .z members of type T (and has exactly the size of a `T[3]`). This will
238  /// implicitly convert from an Imath::Vector3<T>, among other things.
240  OIIO_HOSTDEVICE constexpr Vec3Param(const V& v) noexcept
241  : x(v.x)
242  , y(v.y)
243  , z(v.z)
244  {
245  }
246 
247  /// Construct from anything that looks like a 3-vector, having `[]`
248  /// component access returning a `T`, and has exactly the size of a
249  /// `T[3]`.
252  OIIO_HOSTDEVICE constexpr Vec3Param(const V& v) noexcept
253  : x(v[0])
254  , y(v[1])
255  , z(v[2])
256  {
257  }
258 
259 #ifdef INCLUDED_IMATHVEC_H
260  /// Only if ImathVec.h has been included, we can construct a Vec3Param<T>
261  /// out of an Imath::Vec3<T>.
262  OIIO_HOSTDEVICE constexpr operator const Imath::Vec3<T>&() const noexcept
263  {
264  return *(const Imath::Vec3<T>*)this;
265  }
266 
267  /// Only if ImathVec.h has been included, we can implicitly convert a
268  /// `Vec3Param<T>` to a `Imath::Vec3<T>`.
269  OIIO_HOSTDEVICE constexpr const Imath::Vec3<T>& operator()() const noexcept
270  {
271  return *(const Imath::Vec3<T>*)this;
272  }
273 #endif
274 
275  // Return a reference to the contiguous values comprising the matrix.
276  template<typename V, OIIO_ENABLE_IF(sizeof(V) == 3 * sizeof(T))>
277  constexpr const V& cast() const noexcept
278  {
279  const char* p = (const char*)this;
280  return *(const V*)p;
281  }
282 
283  /// Implicitly convert a `Vec3Param<T>` to a `const V&` for a V that looks
284  /// like a 3-vector.
287  OIIO_HOSTDEVICE constexpr operator const V&() const noexcept
288  {
289  return cast<V>();
290  }
291 
292  // The internal representation is just the 3 values.
293  T x, y, z;
294 };
295 
296 
297 /// V3fParam is an alias for Vec3Param<float>
299 
300 
301 
302 /// MatrixParam is a helper template that lets us create an interface that
303 /// takes a proxy for a `T[S][S]` analogue for use as a public API function
304 /// parameter type to pass a square matrix, in order to not expose the
305 /// underlying matrix types. The common cases are given handy aliases:
306 /// M33fParam and M33fParam for 3x3 and 4x4 float matrices, respectively
307 /// (`MatrixParam<float,3>` and `MatrixParam<float,4>` are the long names).
308 ///
309 /// For example, suppose we have a public function like this:
310 ///
311 /// void foo(M33fParam v);
312 ///
313 /// Then any of the following calls will work:
314 ///
315 /// float array[3][3];
316 /// foo(array);
317 ///
318 /// foo(Imath::M33f(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1));
319 ///
320 template<typename T, int S> class MatrixParam {
321 public:
322  static constexpr int Size = S;
323 
324  /// We can construct a MatrixParam out of anything that has the size
325  /// of a `T[S][S]` and presents a `[][]` subscript operator.
326  template<typename M,
328  OIIO_HOSTDEVICE constexpr MatrixParam(const M& m) noexcept
329  : m_ptr((const T*)&m)
330  {
331  }
332 
333 #ifdef INCLUDED_IMATHMATRIX_H
334  /// Only if ImathMatrix.h has been included, we can construct a
335  /// MatrixParam<T,3> out of an Imath::Matrix33<T>.
336  template<typename ThisType = MatrixParam,
338  OIIO_HOSTDEVICE constexpr
339  operator const Imath::Matrix33<T>&() const noexcept
340  {
341  return *(const Imath::Matrix33<T>*)(m_ptr);
342  }
343 
344  /// Only if ImathMatrix.h has been included, we can implicitly convert a
345  /// MatrixParam<T,3> into an Imath::Matrix33<T>.
346  template<typename ThisType = MatrixParam,
348  OIIO_HOSTDEVICE constexpr const Imath::Matrix33<T>&
349  operator()() const noexcept
350  {
351  return *(const Imath::Matrix33<T>*)(m_ptr);
352  }
353 
354  /// Only if ImathMatrix.h has been included, we can construct a
355  /// MatrixParam<T,4> out of an Imath::Matrix44<T>.
356  template<typename ThisType = MatrixParam,
358  OIIO_HOSTDEVICE constexpr
359  operator const Imath::Matrix44<T>&() const noexcept
360  {
361  return *(const Imath::Matrix44<T>*)(m_ptr);
362  }
363 
364  /// Only if ImathMatrix.h has been included, we can implicitly convert a
365  /// MatrixParam<T,4> into an Imath::Matrix44<T>.
366  template<typename ThisType = MatrixParam,
368  OIIO_HOSTDEVICE constexpr const Imath::Matrix44<T>&
369  operator()() const noexcept
370  {
371  return *(const Imath::Matrix44<T>*)(m_ptr);
372  }
373 #endif
374 
375  /// Return a pointer to the contiguous values comprising the matrix.
376  const T* data() const noexcept { return m_ptr; }
377 
378 private:
379  /// Underlying representation is just a pointer.
380  const T* m_ptr;
381 };
382 
383 
384 /// M33fParam is an alias for MatrixParam<float, 3>
386 
387 /// M44fParam is an alias for MatrixParam<float, 4>
389 
390 
type
Definition: core.h:556
const GLdouble * v
Definition: glcorearb.h:837
GLsizei const GLfloat * value
Definition: glcorearb.h:824
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:848
#define OIIO_ENABLE_IF(...)
Definition: platform.h:676
GLint y
Definition: glcorearb.h:103
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
#define OIIO_HOSTDEVICE
Definition: platform.h:529
GLint GLenum GLint x
Definition: glcorearb.h:409
OIIO_HOSTDEVICE constexpr Vec3Param(const V &v) noexcept
Definition: vecparam.h:240
const T * data() const noexcept
Return a pointer to the contiguous values comprising the matrix.
Definition: vecparam.h:376
constexpr const V & cast() const noexcept
Definition: vecparam.h:277
OIIO_HOSTDEVICE constexpr Vec3Param(T x, T y, T z) noexcept
Construct directly from 3 floats.
Definition: vecparam.h:229
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:857
#define OIIO_NAMESPACE_END
Definition: oiioversion.h:127
#define OIIO_NAMESPACE_BEGIN
Definition: oiioversion.h:126
OIIO_HOSTDEVICE constexpr MatrixParam(const M &m) noexcept
Definition: vecparam.h:328