pick.hh 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // -*- mode: c++; coding: utf-8 -*-
  2. /// @file pick.hh
  3. /// @brief Expression template that picks one of several arguments.
  4. // (c) Daniel Llorens - 2016-2017, 2019
  5. // This library is free software; you can redistribute it and/or modify it under
  6. // the terms of the GNU General Public License as published by the Free
  7. // Software Foundation; either version 3 of the License, or (at your option) any
  8. // later version.
  9. // This class is needed because Expr evaluates its arguments before calling its
  10. // operator. The implementation itself is parallel to Expr / Flat. Note that
  11. // pick() is a normal function, so its *arguments* will always be evaluated; it
  12. // is the individual array elements that will not be.
  13. #pragma once
  14. #include "ra/ply.hh"
  15. #include "ra/match.hh"
  16. namespace ra {
  17. // -----------------
  18. // return type of pick expression, otherwise compiler complains of ambiguity.
  19. // TODO & is crude, maybe is_assignable?
  20. // -----------------
  21. template <class T>
  22. struct pick_type
  23. {
  24. using type = mp::apply<std::common_type_t, T>;
  25. };
  26. // lvalue
  27. template <class P0, class ... P>
  28. requires (!std::is_const_v<P0> && (std::is_same_v<P0 &, P> && ...))
  29. struct pick_type<std::tuple<P0 &, P ...>>
  30. {
  31. using type = P0 &;
  32. };
  33. // const lvalue
  34. template <class P0, class ... P>
  35. requires ((std::is_same_v<std::decay_t<P0>, std::decay_t<P>> && ...)
  36. && (std::is_const_v<P0> || (std::is_const_v<P> || ...)))
  37. struct pick_type<std::tuple<P0 &, P & ...>>
  38. {
  39. using type = P0 const &;
  40. };
  41. // -----------------
  42. // runtime to compile time conversion for Pick::at() and PickFlat::operator*()
  43. // -----------------
  44. template <class T, class J> struct pick_at_type;
  45. template <class ... P, class J> struct pick_at_type<std::tuple<P ...>, J>
  46. {
  47. using type = typename pick_type<std::tuple<decltype(std::declval<P>().at(std::declval<J>())) ...>>::type;
  48. };
  49. template <class T, class J> using pick_at_t = typename pick_at_type<mp::drop1<std::decay_t<T>>, J>::type;
  50. template <size_t I, class T, class J> inline constexpr
  51. pick_at_t<T, J>
  52. pick_at(size_t p0, T && t, J const & j)
  53. {
  54. if constexpr (I+2<std::tuple_size_v<std::decay_t<T>>) {
  55. if (p0==I) {
  56. return std::get<I+1>(t).at(j);
  57. } else {
  58. return pick_at<I+1>(p0, t, j);
  59. }
  60. } else {
  61. RA_CHECK(p0==I, " p0 ", p0, " I ", I);
  62. return std::get<I+1>(t).at(j);
  63. }
  64. }
  65. template <class T> struct pick_star_type;
  66. template <class ... P> struct pick_star_type<std::tuple<P ...>>
  67. {
  68. using type = typename pick_type<std::tuple<decltype(*std::declval<P>()) ...>>::type;
  69. };
  70. template <class T> using pick_star_t = typename pick_star_type<mp::drop1<std::decay_t<T>>>::type;
  71. template <size_t I, class T> inline constexpr
  72. pick_star_t<T>
  73. pick_star(size_t p0, T && t)
  74. {
  75. if constexpr (I+2<std::tuple_size_v<std::decay_t<T>>) {
  76. if (p0==I) {
  77. return *(std::get<I+1>(t));
  78. } else {
  79. return pick_star<I+1>(p0, t);
  80. }
  81. } else {
  82. RA_CHECK(p0==I, " p0 ", p0, " I ", I);
  83. return *(std::get<I+1>(t));
  84. }
  85. }
  86. // Manipulate ET through flat (raw pointer-like) iterators P ...
  87. template <class T, class I=mp::iota<mp::len<T>>>
  88. struct PickFlat;
  89. template <class P0, class ... P, int ... I>
  90. struct PickFlat<std::tuple<P0, P ...>, mp::int_list<I ...>>
  91. {
  92. std::tuple<P0, P ...> t;
  93. template <class S> void operator+=(S const & s) { ((std::get<I>(t) += std::get<I>(s)), ...); }
  94. decltype(auto) operator*() { return pick_star<0>(*std::get<0>(t), t); }
  95. };
  96. template <class P0, class ... P> inline constexpr auto
  97. pick_flat(P0 && p0, P && ... p)
  98. {
  99. return PickFlat<std::tuple<P0, P ...>> { std::tuple<P0, P ...> { std::forward<P0>(p0), std::forward<P>(p) ... } };
  100. }
  101. // forward decl in atom.hh
  102. template <class P0, class ... P, int ... I>
  103. struct Pick<std::tuple<P0, P ...>, mp::int_list<I ...>>: public Match<std::tuple<P0, P ...>>
  104. {
  105. using Match_ = Match<std::tuple<P0, P ...>>;
  106. // test/ra-9.cc [ra1] for forward() here.
  107. constexpr Pick(P0 p0_, P ... p_): Match_(std::forward<P0>(p0_), std::forward<P>(p_) ...) {}
  108. template <class J> constexpr decltype(auto)
  109. at(J const & j)
  110. {
  111. return pick_at<0>(std::get<0>(this->t).at(j), this->t, j);
  112. }
  113. constexpr auto
  114. flat()
  115. {
  116. return pick_flat(std::get<I>(this->t).flat() ...);
  117. }
  118. // needed for xpr with rank_s()==RANK_ANY, which don't decay to scalar when used as operator arguments.
  119. using scalar = decltype(*(pick_flat(std::get<I>(Match_::t).flat() ...)));
  120. operator scalar()
  121. {
  122. if constexpr (this->rank_s()!=1 || size_s(*this)!=1) { // for coord types; so fixed only
  123. if constexpr (this->rank_s()!=0) {
  124. static_assert(this->rank_s()==RANK_ANY);
  125. assert(this->rank()==0);
  126. }
  127. }
  128. return *flat();
  129. }
  130. FOR_EACH(RA_DEF_ASSIGNOPS, =, *=, +=, -=, /=)
  131. };
  132. template <class P0, class ... P> inline constexpr auto
  133. pick_in(P0 && p0, P && ... p)
  134. {
  135. return Pick<std::tuple<P0, P ...>> { std::forward<P0>(p0), std::forward<P>(p) ... };
  136. }
  137. template <class P0, class ... P> inline constexpr auto
  138. pick(P0 && p0, P && ... p)
  139. {
  140. return pick_in(start(std::forward<P0>(p0)), start(std::forward<P>(p)) ...);
  141. }
  142. } // namespace ra