Wayverb
traits.h
1 #pragma once
2 
3 #include "core/cl/include.h"
4 
5 #include "utilities/foldl.h"
6 
7 #include <algorithm>
8 #include <cmath>
9 #include <functional>
10 #include <type_traits>
11 
12 // Most of this has to live in the global namespace because the cl_* types
13 // live in the global namespace, and we want name lookup to work.
14 
15 #define CL_UNIT(cl_type) \
16  struct cl_type##1 final { \
17  cl_type s[1]; \
18  };
19 
20 #define CL_FOR_EACH_TYPE(macro) \
21  macro(cl_char) macro(cl_uchar) macro(cl_short) macro(cl_ushort) \
22  macro(cl_int) macro(cl_uint) macro(cl_long) macro(cl_ulong) \
23  macro(cl_float) macro(cl_double)
24 
25 CL_FOR_EACH_TYPE(CL_UNIT)
26 
27 // macro machinery ////////////////////////////////////////////////////////////
28 
29 #define CL_VECTOR_REGISTER_PREFIX(macro, cl_type_prefix_) \
30  macro(cl_type_prefix_##1) macro(cl_type_prefix_##2) \
31  macro(cl_type_prefix_##4) macro(cl_type_prefix_##8) \
32  macro(cl_type_prefix_##16)
33 
34 #define CL_VECTOR_REGISTER(macro) \
35  CL_VECTOR_REGISTER_PREFIX(macro, cl_char) \
36  CL_VECTOR_REGISTER_PREFIX(macro, cl_uchar) \
37  CL_VECTOR_REGISTER_PREFIX(macro, cl_short) \
38  CL_VECTOR_REGISTER_PREFIX(macro, cl_ushort) \
39  CL_VECTOR_REGISTER_PREFIX(macro, cl_int) \
40  CL_VECTOR_REGISTER_PREFIX(macro, cl_uint) \
41  CL_VECTOR_REGISTER_PREFIX(macro, cl_long) \
42  CL_VECTOR_REGISTER_PREFIX(macro, cl_ulong) \
43  CL_VECTOR_REGISTER_PREFIX(macro, cl_float) \
44  CL_VECTOR_REGISTER_PREFIX(macro, cl_double)
45 
46 namespace detail {
47 
48 // find properties, given cl vector type //////////////////////////////////////
49 
50 template <typename T>
51 struct cl_vector_type_trait final {
52  using is_vector_type = std::false_type;
53  using value_type = T;
54  using components = std::integral_constant<size_t, 1>;
55 };
56 
57 #define DEFINE_CL_VECTOR_TYPE_TRAIT(cl_type) \
58  template <> \
59  struct cl_vector_type_trait<cl_type> final { \
60  using is_vector_type = std::true_type; \
61  using array_type = decltype(std::declval<cl_type>().s); \
62  static_assert(std::rank<array_type>::value == 1, \
63  "vector types have array rank 1"); \
64  using value_type = std::remove_all_extents_t<array_type>; \
65  using components = \
66  std::integral_constant<size_t, \
67  std::extent<array_type, 0>::value>; \
68  };
69 
70 CL_VECTOR_REGISTER(DEFINE_CL_VECTOR_TYPE_TRAIT)
71 
72 template <typename T>
73 using is_vector_type_t = typename cl_vector_type_trait<T>::is_vector_type;
74 
75 template <typename T>
76 constexpr auto is_vector_type_v = is_vector_type_t<T>{};
77 
78 template <typename T, typename U = void>
79 using enable_if_is_vector_t = std::enable_if_t<is_vector_type_v<T>, U>;
80 
81 template <typename T, typename U = void>
82 using enable_if_is_not_vector_t = std::enable_if_t<!is_vector_type_v<T>, U>;
83 
84 template <typename T>
85 using components_t = typename cl_vector_type_trait<T>::components;
86 
87 template <typename T>
88 constexpr auto components_v = components_t<T>{};
89 
90 template <typename T>
91 using value_type_t = typename cl_vector_type_trait<T>::value_type;
92 
93 template <typename...>
94 struct any;
95 
96 template <typename... Ts>
97 constexpr auto any_v = any<Ts...>::value;
98 
99 template <typename T>
100 struct any<T> final {
101  static constexpr auto value = T::value;
102 };
103 
104 template <typename T, typename... Ts>
105 struct any<T, Ts...> final {
106  static constexpr auto value = any_v<T> || any_v<Ts...>;
107 };
108 
109 template <typename U, typename... Ts>
110 using enable_if_any_is_vector_t =
111  std::enable_if_t<any_v<is_vector_type_t<Ts>...>, U>;
112 
113 // constructing from type + size //////////////////////////////////////////////
114 
115 template <typename T, size_t N>
117 
118 #define DEFINE_CL_VECTOR_CONSTRUCTOR_TRAIT(cl_type) \
119  template <> \
120  struct cl_vector_constructor<value_type_t<cl_type>, components_v<cl_type>> \
121  final { \
122  using type = cl_type; \
123  };
124 
125 CL_VECTOR_REGISTER(DEFINE_CL_VECTOR_CONSTRUCTOR_TRAIT)
126 
127 template <typename T, size_t N>
128 using cl_vector_constructor_t = typename cl_vector_constructor<T, N>::type;
129 
130 template <size_t N>
131 struct cl_vector_constructor<bool, N> final {
132  using type = cl_vector_constructor_t<cl_char, N>;
133 };
134 
135 template <typename T, typename Op, enable_if_is_vector_t<T, int> = 0>
136 constexpr auto accumulate(const T& t, const Op& op) {
137  return util::foldl(op, t.s);
138 }
139 
140 template <typename T,
141  typename Accumulator,
142  typename Op,
143  enable_if_is_vector_t<T, int> = 0>
144 constexpr auto accumulate(const T& t,
145  const Accumulator& accumulator,
146  const Op& op) {
147  return util::foldl(op, accumulator, t.s);
148 }
149 
150 template <typename T, typename U, typename Op, size_t... Ix>
151 constexpr auto& inplace_zip_both_vector(T& t,
152  const U& u,
153  const Op& op,
154  std::index_sequence<Ix...>) {
155  return t = T{{static_cast<value_type_t<T>>(op(t.s[Ix], u.s[Ix]))...}};
156 }
157 
158 template <typename T,
159  typename U,
160  typename Op,
161  enable_if_is_vector_t<U, int> = 0>
162 constexpr auto& inplace_zip(T& t, const U& u, const Op& op) {
163  return inplace_zip_both_vector(
164  t, u, op, std::make_index_sequence<components_v<T>>{});
165 }
166 
167 template <typename T, typename U, typename Op, size_t... Ix>
168 constexpr auto& inplace_zip_one_vector(T& t,
169  const U& u,
170  const Op& op,
171  std::index_sequence<Ix...>) {
172  return t = T{{static_cast<value_type_t<T>>(op(t.s[Ix], u))...}};
173 }
174 
175 template <typename T,
176  typename U,
177  typename Op,
178  enable_if_is_not_vector_t<U, int> = 0>
179 constexpr auto& inplace_zip(T& t, const U& u, const Op& op) {
180  return inplace_zip_one_vector(
181  t, u, op, std::make_index_sequence<components_v<T>>{});
182 }
183 
184 template <typename T, typename U, typename Op, size_t... Ix>
185 constexpr auto zip_both_vector(const T& t,
186  const U& u,
187  const Op& op,
188  std::index_sequence<Ix...>) {
189  using value_type = std::decay_t<decltype(op(t.s[0], u.s[0]))>;
190  return cl_vector_constructor_t<value_type, sizeof...(Ix)>{
191  {op(t.s[Ix], u.s[Ix])...}};
192 }
193 
194 template <typename T,
195  typename U,
196  typename Op,
197  std::enable_if_t<is_vector_type_v<T> && is_vector_type_v<U> &&
198  components_v<T> == components_v<U>,
199  int> = 0>
200 constexpr auto zip(const T& t, const U& u, const Op& op) {
201  return zip_both_vector(
202  t, u, op, std::make_index_sequence<components_v<T>>{});
203 }
204 
205 template <typename T, typename U, typename Op, size_t... Ix>
206 constexpr auto zip_first_vector(const T& t,
207  const U& u,
208  const Op& op,
209  std::index_sequence<Ix...>) {
210  using value_type = std::decay_t<decltype(op(t.s[0], u))>;
211  return cl_vector_constructor_t<value_type, sizeof...(Ix)>{
212  {op(t.s[Ix], u)...}};
213 }
214 
215 template <
216  typename T,
217  typename U,
218  typename Op,
219  std::enable_if_t<is_vector_type_v<T> && !is_vector_type_v<U>, int> = 0>
220 constexpr auto zip(const T& t, const U& u, const Op& op) {
221  return zip_first_vector(
222  t, u, op, std::make_index_sequence<components_v<T>>{});
223 }
224 
225 template <typename T, typename U, typename Op, size_t... Ix>
226 constexpr auto zip_second_vector(const T& t,
227  const U& u,
228  const Op& op,
229  std::index_sequence<Ix...>) {
230  using value_type = std::decay_t<decltype(op(t, u.s[0]))>;
231  return cl_vector_constructor_t<value_type, sizeof...(Ix)>{
232  {op(t, u.s[Ix])...}};
233 }
234 
235 template <
236  typename T,
237  typename U,
238  typename Op,
239  std::enable_if_t<!is_vector_type_v<T> && is_vector_type_v<U>, int> = 0>
240 constexpr auto zip(const T& t, const U& u, const Op& op) {
241  return zip_second_vector(
242  t, u, op, std::make_index_sequence<components_v<U>>{});
243 }
244 
245 template <typename T, typename Op, size_t... Ix>
246 constexpr auto map_impl(const T& t, const Op& op, std::index_sequence<Ix...>) {
247  using value_type = std::decay_t<decltype(op(t.s[0]))>;
248  return cl_vector_constructor_t<value_type, sizeof...(Ix)>{{op(t.s[Ix])...}};
249 }
250 
251 template <typename T, typename Op, enable_if_is_vector_t<T, int> = 0>
252 constexpr auto map(const T& t, const Op& op) {
253  return map_impl(t, op, std::make_index_sequence<components_v<T>>{});
254 }
255 
256 } // namespace detail
257 
258 // other reductions ///////////////////////////////////////////////////////////
259 
260 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
261 constexpr auto sum(const T& t) {
262  return detail::accumulate(t, std::plus<>{});
263 }
264 
265 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
266 constexpr auto product(const T& t) {
267  return detail::accumulate(t, std::multiplies<>{});
268 }
269 
270 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
271 constexpr auto mean(const T& t) {
272  return sum(t) / detail::components_v<T>;
273 }
274 
275 // logical reductions /////////////////////////////////////////////////////////
276 
277 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
278 constexpr bool all(const T& t) {
279  return detail::accumulate(t, std::logical_and<>{});
280 }
281 
282 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
283 constexpr bool any(const T& t) {
284  return detail::accumulate(t, std::logical_or<>{});
285 }
286 
287 namespace detail {
288 
289 struct max_functor final {
290  template <typename T>
291  constexpr const auto& operator()(const T& a, const T& b) const {
292  using std::max;
293  return max(a, b);
294  }
295 };
296 
297 struct min_functor final {
298  template <typename T>
299  constexpr const auto& operator()(const T& a, const T& b) const {
300  using std::min;
301  return min(a, b);
302  }
303 };
304 
305 } // namespace detail
306 
307 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
308 constexpr auto min_element(const T& t) {
309  return detail::accumulate(t, detail::min_functor{});
310 }
311 
312 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
313 constexpr auto max_element(const T& t) {
314  return detail::accumulate(t, detail::max_functor{});
315 }
316 
317 // misc ///////////////////////////////////////////////////////////////////////
318 
319 template <typename T,
320  size_t components = detail::components_v<T>,
321  detail::enable_if_is_vector_t<T, int> = 0>
322 constexpr auto isnan(const T& t) {
323  return detail::map(t, [](auto i) { return std::isnan(i); });
324 }
325 
326 template <typename T,
327  size_t components = detail::components_v<T>,
328  detail::enable_if_is_vector_t<T, int> = 0>
329 constexpr auto isinf(const T& t) {
330  return detail::map(t, [](auto i) { return std::isinf(i); });
331 }
332 
333 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
334 inline auto sqrt(const T& t) {
335  return detail::map(t, [](auto i) { return std::sqrt(i); });
336 }
337 
338 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
339 inline auto log(const T& t) {
340  return detail::map(t, [](auto i) { return std::log(i); });
341 }
342 
343 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
344 inline auto abs(const T& t) {
345  return detail::map(t, [](auto i) { return std::abs(i); });
346 }
347 
348 template <typename T,
349  typename U,
350  detail::enable_if_any_is_vector_t<int, T, U> = 0>
351 inline auto copysign(const T& t, const U& u) {
352  return detail::zip(
353  t, u, [](auto i, auto j) { return std::copysign(i, j); });
354 }
355 
356 template <typename T,
357  typename U,
358  detail::enable_if_any_is_vector_t<int, T, U> = 0>
359 inline auto pow(const T& t, const U& u) {
360  return detail::zip(t, u, [](auto i, auto j) { return std::pow(i, j); });
361 }
362 
363 template <typename T,
364  typename U,
365  detail::enable_if_any_is_vector_t<int, T, U> = 0>
366 inline auto max(const T& t, const U& u) {
367  return detail::zip(t, u, detail::max_functor{});
368 }
369 
370 template <typename T,
371  typename U,
372  detail::enable_if_any_is_vector_t<int, T, U> = 0>
373 inline auto min(const T& t, const U& u) {
374  return detail::zip(t, u, detail::min_functor{});
375 }
376 
377 template <size_t Components, typename Input>
378 constexpr auto construct_vector(Input input) {
379  detail::cl_vector_constructor_t<Input, Components> ret{};
380  for (auto& i : ret.s) {
381  i = input;
382  }
383  return ret;
384 }
385 
386 // operator overloads /////////////////////////////////////////////////////////
387 
388 template <typename T,
389  typename U,
390  detail::enable_if_any_is_vector_t<int, T, U> = 0>
391 constexpr auto operator==(const T& a, const U& b) {
392  return detail::accumulate(detail::zip(a, b, std::equal_to<>{}),
393  std::logical_and<>{});
394 }
395 
396 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
397 constexpr auto operator!(const T& a) {
398  return detail::map(a, std::logical_not<>{});
399 }
400 
401 template <typename T,
402  typename U,
403  detail::enable_if_any_is_vector_t<int, T, U> = 0>
404 constexpr auto operator!=(const T& a, const U& b) {
405  return !(a == b);
406 }
407 
408 template <typename T,
409  typename U,
410  detail::enable_if_any_is_vector_t<int, T, U> = 0>
411 constexpr auto operator<(const T& a, const U& b) {
412  return detail::zip(a, b, std::less<>{});
413 }
414 
415 template <typename T,
416  typename U,
417  detail::enable_if_any_is_vector_t<int, T, U> = 0>
418 constexpr auto operator<=(const T& a, const U& b) {
419  return detail::zip(a, b, std::less_equal<>{});
420 }
421 
422 // arithmetic ops /////////////////////////////////////////////////////////////
423 
424 template <typename T, typename U, detail::enable_if_is_vector_t<T, int> = 0>
425 constexpr auto& operator+=(T& a, const U& b) {
426  return detail::inplace_zip(a, b, std::plus<>{});
427 }
428 
429 template <typename T, typename U, detail::enable_if_is_vector_t<T, int> = 0>
430 constexpr auto& operator-=(T& a, const U& b) {
431  return detail::inplace_zip(a, b, std::minus<>{});
432 }
433 
434 template <typename T, typename U, detail::enable_if_is_vector_t<T, int> = 0>
435 constexpr auto& operator*=(T& a, const U& b) {
436  return detail::inplace_zip(a, b, std::multiplies<>{});
437 }
438 
439 template <typename T, typename U, detail::enable_if_is_vector_t<T, int> = 0>
440 constexpr auto& operator/=(T& a, const U& b) {
441  return detail::inplace_zip(a, b, std::divides<>{});
442 }
443 
444 template <typename T, typename U, detail::enable_if_is_vector_t<T, int> = 0>
445 constexpr auto& operator%=(T& a, const U& b) {
446  return detail::inplace_zip(a, b, std::modulus<>{});
447 }
448 
450 
451 template <typename T,
452  typename U,
453  detail::enable_if_any_is_vector_t<int, T, U> = 0>
454 constexpr auto operator+(const T& a, const U& b) {
455  return detail::zip(a, b, std::plus<>{});
456 }
457 
458 template <typename T,
459  typename U,
460  detail::enable_if_any_is_vector_t<int, T, U> = 0>
461 constexpr auto operator-(const T& a, const U& b) {
462  return detail::zip(a, b, std::minus<>{});
463 }
464 
465 template <typename T,
466  typename U,
467  detail::enable_if_any_is_vector_t<int, T, U> = 0>
468 constexpr auto operator*(const T& a, const U& b) {
469  return detail::zip(a, b, std::multiplies<>{});
470 }
471 
472 template <typename T,
473  typename U,
474  detail::enable_if_any_is_vector_t<int, T, U> = 0>
475 constexpr auto operator/(const T& a, const U& b) {
476  return detail::zip(a, b, std::divides<>{});
477 }
478 
479 template <typename T,
480  typename U,
481  detail::enable_if_any_is_vector_t<int, T, U> = 0>
482 constexpr auto operator%(const T& a, const U& b) {
483  return detail::zip(a, b, std::modulus<>{});
484 }
485 
486 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
487 constexpr auto operator+(const T& a) {
488  return a;
489 }
490 
491 template <typename T, detail::enable_if_is_vector_t<T, int> = 0>
492 constexpr auto operator-(const T& a) {
493  return detail::map(a, std::negate<>{});
494 }
Definition: traits.h:94
Definition: traits.h:289
Definition: traits.h:297
Definition: traits.h:46
Definition: traits.h:51
Definition: traits.h:116