pick.hh 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra - Expression template that selects an argument.
  3. // (c) Daniel Llorens - 2016-2023
  4. // This library is free software; you can redistribute it and/or modify it under
  5. // the terms of the GNU General Public License as published by the Free
  6. // Software Foundation; either version 3 of the License, or (at your option) any
  7. // later version.
  8. // In contrast to Expr, argument expressions are only evaluated where the
  9. // selector indicates. The implementation is parallel to Expr / Flat.
  10. #pragma once
  11. #include "match.hh"
  12. namespace ra {
  13. template <class T, class J> struct pick_at_type;
  14. template <class ... P, class J> struct pick_at_type<std::tuple<P ...>, J>
  15. {
  16. using type = mp::apply<std::common_reference_t, std::tuple<decltype(std::declval<P>().at(std::declval<J>())) ...>>;
  17. };
  18. template <std::size_t I, class T, class J>
  19. constexpr pick_at_type<mp::drop1<std::decay_t<T>>, J>::type
  20. pick_at(std::size_t p0, T && t, J const & j)
  21. {
  22. if constexpr (I+2<std::tuple_size_v<std::decay_t<T>>) {
  23. if (p0==I) {
  24. return std::get<I+1>(t).at(j);
  25. } else {
  26. return pick_at<I+1>(p0, t, j);
  27. }
  28. } else {
  29. RA_CHECK(p0==I, " p0 ", p0, " I ", I);
  30. return std::get<I+1>(t).at(j);
  31. }
  32. }
  33. template <class T> struct pick_star_type;
  34. template <class ... P> struct pick_star_type<std::tuple<P ...>>
  35. {
  36. using type = mp::apply<std::common_reference_t, std::tuple<decltype(*std::declval<P>()) ...>>;
  37. };
  38. template <std::size_t I, class T>
  39. constexpr pick_star_type<mp::drop1<std::decay_t<T>>>::type
  40. pick_star(std::size_t p0, T && t)
  41. {
  42. if constexpr (I+2<std::tuple_size_v<std::decay_t<T>>) {
  43. if (p0==I) {
  44. return *(std::get<I+1>(t));
  45. } else {
  46. return pick_star<I+1>(p0, t);
  47. }
  48. } else {
  49. RA_CHECK(p0==I, " p0 ", p0, " I ", I);
  50. return *(std::get<I+1>(t));
  51. }
  52. }
  53. template <class T, class K=mp::iota<mp::len<T>>> struct Pick;
  54. template <IteratorConcept ... P, int ... I>
  55. struct Pick<std::tuple<P ...>, mp::int_list<I ...>>: public Match<true, std::tuple<P ...>>
  56. {
  57. static_assert(sizeof...(P)>1);
  58. template <class T_>
  59. struct Flat
  60. {
  61. T_ t;
  62. template <class S> constexpr void operator+=(S const & s) { ((std::get<I>(t) += std::get<I>(s)), ...); }
  63. constexpr decltype(auto) operator*() { return pick_star<0>(*std::get<0>(t), t); }
  64. };
  65. template <class ... P_>
  66. constexpr static auto
  67. flat(P_ && ... p)
  68. {
  69. return Flat<std::tuple<P_ ...>> { std::tuple<P_ ...> { std::forward<P_>(p) ... } };
  70. }
  71. using Match_ = Match<true, std::tuple<P ...>>;
  72. // test/ra-9.cc [ra1]
  73. constexpr Pick(P ... p_): Match_(std::forward<P>(p_) ...) {}
  74. RA_DEF_ASSIGNOPS_SELF(Pick)
  75. RA_DEF_ASSIGNOPS_DEFAULT_SET
  76. constexpr decltype(auto)
  77. flat()
  78. {
  79. return flat(std::get<I>(this->t).flat() ...);
  80. }
  81. constexpr decltype(auto)
  82. at(auto const & j) const
  83. {
  84. return pick_at<0>(std::get<0>(this->t).at(j), this->t, j);
  85. }
  86. // needed for xpr with rank_s()==RANK_ANY, which don't decay to scalar when used as operator arguments.
  87. constexpr
  88. operator decltype(*(flat(std::get<I>(Match_::t).flat() ...))) ()
  89. {
  90. if constexpr (this->rank_s()!=1 || size_s(*this)!=1) { // for coord types; so fixed only
  91. if constexpr (this->rank_s()!=0) {
  92. static_assert(this->rank_s()==RANK_ANY);
  93. assert(this->rank()==0);
  94. }
  95. }
  96. return *flat();
  97. }
  98. };
  99. template <class ... P> Pick(P && ... p) -> Pick<std::tuple<P ...>>;
  100. template <class ... P>
  101. constexpr auto
  102. pick(P && ... p)
  103. {
  104. return Pick { start(std::forward<P>(p)) ... };
  105. }
  106. } // namespace ra