expr.H 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // -*- mode: c++; coding: utf-8 -*-
  2. /// @file expr.H
  3. /// @brief Operator nodes for expression templates.
  4. // (c) Daniel Llorens - 2011-2014, 2016-2017, 2019
  5. // This library is free software; you can redistribute it and/or modify it under
  6. // the terms of the GNU Lesser 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. #pragma once
  10. #include "ra/ply.H"
  11. #include "ra/match.H"
  12. #if defined(RA_CHECK_BOUNDS) && RA_CHECK_BOUNDS==0
  13. #define CHECK_BOUNDS( cond )
  14. #else
  15. #define CHECK_BOUNDS( cond ) RA_ASSERT( cond, 0 )
  16. #endif
  17. namespace ra {
  18. // Manipulate ET through flat (raw pointer-like) iterators P ...
  19. template <class Op, class T, class I=mp::iota<mp::len<T>>> struct Flat;
  20. template <class Op, class T, int ... I>
  21. struct Flat<Op, T, mp::int_list<I ...>>
  22. {
  23. Op & op;
  24. T t;
  25. template <class S> constexpr void operator+=(S const & s) { ((std::get<I>(t) += std::get<I>(s)), ...); }
  26. constexpr decltype(auto) operator*() { return op(*std::get<I>(t) ...); }
  27. };
  28. template <class Op, class ... P> inline constexpr auto
  29. flat(Op & op, P && ... p)
  30. {
  31. return Flat<Op, std::tuple<P ...>> { op, std::tuple<P ...> { std::forward<P>(p) ... } };
  32. }
  33. template <class Op, class ... P> inline constexpr auto
  34. expr(Op && op, P && ... p)
  35. {
  36. return Expr<Op, std::tuple<P ...>> { std::forward<Op>(op), std::forward<P>(p) ... };
  37. }
  38. template <class Op, class ... A> inline constexpr auto
  39. map(Op && op, A && ... a)
  40. {
  41. return expr(std::forward<Op>(op), start(std::forward<A>(a)) ...);
  42. }
  43. template <class Op, class ... A> inline constexpr void
  44. for_each(Op && op, A && ... a)
  45. {
  46. ply(map(std::forward<Op>(op), std::forward<A>(a) ...));
  47. }
  48. // forward decl in atom.H
  49. template <class Op, class ... P, int ... I>
  50. struct Expr<Op, std::tuple<P ...>, mp::int_list<I ...>>: public Match<std::tuple<P ...>>
  51. {
  52. using Match_ = Match<std::tuple<P ...>>;
  53. Op op;
  54. // see test/ra-9.C [ra01] for forward() here.
  55. constexpr Expr(Op op_, P ... p_): Match_(std::forward<P>(p_) ...), op(std::forward<Op>(op_)) {}
  56. template <class J> constexpr decltype(auto)
  57. at(J const & i)
  58. {
  59. return op(std::get<I>(this->t).at(i) ...);
  60. }
  61. constexpr decltype(auto)
  62. flat()
  63. {
  64. return ra::flat(op, std::get<I>(this->t).flat() ...);
  65. }
  66. // needed for xpr with rank_s()==RANK_ANY, which don't decay to scalar when used as operator arguments.
  67. using scalar = decltype(*(ra::flat(op, std::get<I>(Match_::t).flat() ...)));
  68. operator scalar()
  69. {
  70. if constexpr (this->rank_s()!=1 || size_s(*this)!=1) { // for coord types; so fixed only
  71. if constexpr (this->rank_s()!=0) {
  72. static_assert(this->rank_s()==RANK_ANY);
  73. assert(this->rank()==0);
  74. }
  75. }
  76. return *flat();
  77. }
  78. // forward to make sure value y is not misused as ref [ra05].
  79. #define DEF_ASSIGNOPS(OP) template <class X> constexpr void operator OP(X && x) \
  80. { for_each([](auto && y, auto && x) { std::forward<decltype(y)>(y) OP x; }, *this, x); }
  81. FOR_EACH(DEF_ASSIGNOPS, =, *=, +=, -=, /=)
  82. #undef DEF_ASSIGNOPS
  83. };
  84. } // namespace ra
  85. #undef CHECK_BOUNDS