reduction.hpp 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. #ifndef SIMPLE_GEOM_REDUCTION_HPP
  2. #define SIMPLE_GEOM_REDUCTION_HPP
  3. #include <utility>
  4. #include "simple/support/type_traits.hpp"
  5. namespace simple::geom
  6. {
  7. template <typename Range>
  8. using range_value_t = support::remove_cvref_t<
  9. decltype(*std::declval<Range>().begin())
  10. >;
  11. // TODO: in_place version that accepts value by reference?
  12. template <typename Op, typename Value, typename Range,
  13. std::enable_if_t<
  14. std::is_same_v<range_value_t<Range>, Value>
  15. >* = nullptr>
  16. constexpr Value deep_reduce(
  17. const Range& range, Value init = Op::identity )
  18. {
  19. for(auto&& one : range)
  20. init = Op{}(init, one);
  21. return init;
  22. }
  23. template <typename Op, typename Value, typename Range,
  24. std::enable_if_t<
  25. !std::is_same_v<range_value_t<Range>, Value>
  26. // is_range_v<range_value_t<Range>>
  27. >* = nullptr>
  28. constexpr Value deep_reduce(
  29. const Range& range, Value init = Op::identity )
  30. {
  31. for(auto&& one : range)
  32. init = deep_reduce<Op>(one, init);
  33. return init;
  34. }
  35. // NOTE: Not really simple::geom specific, make sense with any range... well except for the weird implicit conversions...
  36. template <typename Operation, typename Range,
  37. typename Value = range_value_t<Range> >
  38. struct reduction {
  39. using value_type = Value;
  40. using range_type = Range;
  41. using operation = Operation;
  42. constexpr static auto identity = Operation::identity;
  43. Range range;
  44. constexpr explicit reduction(Range range) :
  45. range(std::move(range)) {}
  46. constexpr operator Range() const { return range; }
  47. template <typename Other, typename R = Range,
  48. std::enable_if_t<
  49. std::is_constructible_v<Other,R> &&
  50. not support::is_template_instance_v<
  51. simple::geom::reduction, Other
  52. >
  53. > * = nullptr
  54. >
  55. constexpr operator Other() const { return static_cast<Other>(range); }
  56. constexpr explicit operator value_type() const
  57. {
  58. return deep_reduce<operation>(range, identity);
  59. }
  60. [[nodiscard]]
  61. constexpr auto operator ==(const reduction& other) const noexcept
  62. {
  63. return range == other.range;
  64. }
  65. [[nodiscard]]
  66. constexpr auto operator !=(const reduction& other) const noexcept
  67. {
  68. return range != other.range;
  69. }
  70. };
  71. } // namespace simple::geom
  72. #endif /* end of include guard */