type.H 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // (c) Daniel Llorens - 2013-2017
  2. // This library is free software; you can redistribute it and/or modify it under
  3. // the terms of the GNU Lesser General Public License as published by the Free
  4. // Software Foundation; either version 3 of the License, or (at your option) any
  5. // later version.
  6. /// @file type.H
  7. /// @brief Type predicates and use-as-xpr wrapper for foreign types.
  8. #pragma once
  9. #include "ra/atom.H"
  10. #include <iterator>
  11. namespace ra {
  12. #define RA_IS_DEF(NAME, PRED) \
  13. template <class A, class Enable=void> constexpr bool JOIN(NAME, _def) = false; \
  14. template <class A> constexpr bool JOIN(NAME, _def) < A, std::enable_if_t< PRED >> = true; \
  15. template <class A> constexpr bool NAME = JOIN(NAME, _def)< std::decay_t< A >>;
  16. // specialize this for new types for which is_scalar<> should be true. These are foreign types.
  17. RA_IS_DEF(is_scalar, (!std::is_pointer<A>::value && std::is_scalar<A>::value))
  18. // other foreign types we care about.
  19. template <class A> constexpr bool is_foreign_vector_def = false;
  20. template <class A, class Enable=void> constexpr bool is_foreign_vector = is_foreign_vector_def<std::decay_t<A>>;
  21. template <class T, class A> constexpr bool is_foreign_vector_def<std::vector<T, A>> = true;
  22. template <class T, std::size_t N> constexpr bool is_foreign_vector_def<std::array<T, N>> = true;
  23. template <class A> constexpr bool is_builtin_array = std::is_array<std::remove_cv_t<std::remove_reference_t<A>>>::value;
  24. // TODO make things is_iterator explicitly, as with is_scalar, and not by poking in the insides.
  25. // TODO check the rest of the required interface of A and A::flat() right here.
  26. RA_IS_DEF(is_iterator, (mp::exists<decltype(std::declval<A>().flat())>))
  27. RA_IS_DEF(is_ra_scalar, (std::is_same<A, Scalar<typename A::C> >::value))
  28. RA_IS_DEF(is_iterator_pos_rank, is_iterator<A> && A::rank_s()!=0)
  29. RA_IS_DEF(is_slice, (mp::exists<decltype(std::declval<A>().iter())> && mp::exists<decltype(ra_traits<A>::size_s())>)) // reject public-derived from A
  30. RA_IS_DEF(is_slice_pos_rank, is_slice<A> && A::rank_s()!=0)
  31. template <class A> constexpr bool is_ra = is_iterator<A> || is_slice<A>;
  32. template <class A> constexpr bool is_ra_pos_rank = is_iterator_pos_rank<A> || is_slice_pos_rank<A>;
  33. template <class A> constexpr bool is_ra_zero_rank = is_ra<A> && !is_ra_pos_rank<A>;
  34. template <class A> constexpr bool is_zero_or_scalar = is_ra_zero_rank<A> || is_scalar<A>;
  35. #undef RA_IS_DEF
  36. // --------------
  37. // to provide extension of scalar functions to ra:: types
  38. // --------------
  39. template <class ... A> constexpr bool ra_pos_and_any = (is_ra_pos_rank<A> || ...) && ((is_ra<A> || is_scalar<A> || is_foreign_vector<A> || is_builtin_array<A>) && ...);
  40. // all args have rank 0 (so immediate application), but at least one is ra:: (don't collide with the scalar version).
  41. template <class ... A> constexpr bool ra_zero = !(is_scalar<A> && ...) && (is_zero_or_scalar<A> && ...);
  42. template <class T>
  43. struct ra_traits_def<T, std::enable_if_t<is_scalar<T>>>
  44. {
  45. using V = T;
  46. using value_type = T;
  47. constexpr static dim_t size(V const & v) { return 1; }
  48. constexpr static dim_t size_s() { return 1; }
  49. constexpr static rank_t rank(V const & v) { return 0; }
  50. constexpr static rank_t rank_s() { return 0; }
  51. };
  52. // --------------
  53. // Coerce potential ArrayIterators
  54. // --------------
  55. template <class T, int a>
  56. inline constexpr auto start(T && t)
  57. {
  58. static_assert(!mp::exists<T>, "bad type for ra:: operator");
  59. }
  60. // it matters that this copies when T is lvalue. But FIXME shouldn't be necessary.
  61. template <class T, std::enable_if_t<is_iterator<T> && !is_ra_scalar<T>, int> = 0>
  62. inline constexpr auto start(T && t)
  63. {
  64. return std::forward<T>(t);
  65. }
  66. template <class T, std::enable_if_t<is_ra_scalar<T>, int> =0>
  67. inline constexpr decltype(auto) start(T && t)
  68. {
  69. return std::forward<T>(t);
  70. }
  71. template <class T, std::enable_if_t<is_slice<T>, int> = 0>
  72. inline constexpr auto start(T && t)
  73. {
  74. return t.iter(); // BUG if t is rvalue, t.iter() won't retain it. See test-ra-7.C [opt-small].
  75. }
  76. template <class T, std::enable_if_t<is_scalar<T>, int> = 0>
  77. inline constexpr auto start(T && t)
  78. {
  79. return ra::scalar(std::forward<T>(t));
  80. }
  81. template <class T, std::enable_if_t<is_foreign_vector<T>, int> = 0>
  82. inline constexpr auto start(T && t)
  83. {
  84. return Vector<T> { std::forward<T>(t) };
  85. }
  86. template <class T>
  87. inline constexpr auto start(std::initializer_list<T> && v)
  88. {
  89. return Vector<std::initializer_list<T>> { std::move(v) };
  90. }
  91. // forward declare for expr.H; implemented in small.H.
  92. template <class T, std::enable_if_t<is_builtin_array<T>, int> = 0>
  93. inline constexpr auto start(T && t);
  94. // FIXME one of these is ET-generic and the other is slice only, so make up your mind.
  95. // FIXME do we really want to drop const? See use in concrete_type.
  96. template <class A> using value_t = std::decay_t<decltype(*(ra::start(std::declval<A>()).flat()))>;
  97. template <class V> inline auto size(V const & v) { return ra_traits<V>::size(v); }
  98. } // namespace ra