Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

183 lines
5.9KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Mitsutaka Takeda 2018-present
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. #ifndef RANGE_V3_VIEW_EXCLUSIVE_SCAN_HPP
  14. #define RANGE_V3_VIEW_EXCLUSIVE_SCAN_HPP
  15. #include <concepts/concepts.hpp>
  16. #include <range/v3/range_fwd.hpp>
  17. #include <range/v3/functional/arithmetic.hpp>
  18. #include <range/v3/functional/bind_back.hpp>
  19. #include <range/v3/functional/invoke.hpp>
  20. #include <range/v3/view/adaptor.hpp>
  21. #include <range/v3/view/view.hpp>
  22. namespace ranges
  23. {
  24. // clang-format off
  25. CPP_def
  26. (
  27. template(typename Rng, typename T, typename Fun)
  28. concept exclusive_scan_constraints,
  29. viewable_range<Rng> && input_range<Rng> &&
  30. copy_constructible<T> &&
  31. invocable<Fun &, T, range_reference_t<Rng>> &&
  32. assignable_from<T &, invoke_result_t<Fun &, T, range_reference_t<Rng>>>
  33. );
  34. // clang-format on
  35. /// \addtogroup group-views
  36. /// @{
  37. template<typename Rng, typename T, typename Fun>
  38. struct exclusive_scan_view : view_adaptor<exclusive_scan_view<Rng, T, Fun>, Rng>
  39. {
  40. private:
  41. friend range_access;
  42. CPP_assert(exclusive_scan_constraints<Rng, T, Fun>);
  43. semiregular_box_t<T> init_;
  44. semiregular_box_t<Fun> fun_;
  45. using single_pass = meta::bool_<single_pass_iterator_<iterator_t<Rng>>>;
  46. using use_sentinel_t = meta::bool_<!common_range<Rng> || single_pass{}>;
  47. template<bool IsConst>
  48. struct adaptor : adaptor_base
  49. {
  50. private:
  51. friend struct adaptor<!IsConst>;
  52. using exclusive_scan_view_t = meta::const_if_c<IsConst, exclusive_scan_view>;
  53. using CRng = meta::const_if_c<IsConst, Rng>;
  54. semiregular_box_t<T> sum_;
  55. exclusive_scan_view_t * rng_;
  56. // clang-format off
  57. auto CPP_auto_fun(move_or_copy_init)(std::false_type)
  58. (
  59. return (rng_->init_)
  60. )
  61. // If the base range is single-pass, we can move the init value.
  62. auto CPP_auto_fun(move_or_copy_init)(std::true_type)
  63. (
  64. return std::move(rng_->init_)
  65. )
  66. // clang-format on
  67. public : using single_pass = exclusive_scan_view::single_pass;
  68. adaptor() = default;
  69. adaptor(exclusive_scan_view_t * rng)
  70. : rng_(rng)
  71. {}
  72. CPP_template(bool Other)( //
  73. requires IsConst && (!Other)) adaptor(adaptor<Other> that)
  74. : rng_(that.rng_)
  75. {}
  76. iterator_t<CRng> begin(exclusive_scan_view_t &)
  77. {
  78. sum_ = move_or_copy_init(single_pass{});
  79. return ranges::begin(rng_->base());
  80. }
  81. T read(iterator_t<CRng> const &) const
  82. {
  83. return sum_;
  84. }
  85. void next(iterator_t<CRng> & it)
  86. {
  87. RANGES_EXPECT(it != ranges::end(rng_->base()));
  88. sum_ = invoke(rng_->fun_, static_cast<T &&>(std::move(sum_)), *it);
  89. ++it;
  90. }
  91. void prev() = delete;
  92. };
  93. adaptor<false> begin_adaptor()
  94. {
  95. return {this};
  96. }
  97. meta::if_<use_sentinel_t, adaptor_base, adaptor<false>> end_adaptor()
  98. {
  99. return {this};
  100. }
  101. CPP_member
  102. auto begin_adaptor() const -> CPP_ret(adaptor<true>)( //
  103. requires exclusive_scan_constraints<Rng const, T, Fun const>)
  104. {
  105. return {this};
  106. }
  107. CPP_member
  108. auto end_adaptor() const
  109. -> CPP_ret(meta::if_<use_sentinel_t, adaptor_base, adaptor<true>>)( //
  110. requires exclusive_scan_constraints<Rng const, T, Fun const>)
  111. {
  112. return {this};
  113. }
  114. public:
  115. exclusive_scan_view() = default;
  116. constexpr exclusive_scan_view(Rng rng, T init, Fun fun)
  117. : exclusive_scan_view::view_adaptor{std::move(rng)}
  118. , init_(std::move(init))
  119. , fun_(std::move(fun))
  120. {}
  121. CPP_member
  122. auto CPP_fun(size)()(const requires sized_range<Rng const>)
  123. {
  124. return ranges::size(this->base());
  125. }
  126. CPP_member
  127. auto CPP_fun(size)()(requires sized_range<Rng>)
  128. {
  129. return ranges::size(this->base());
  130. }
  131. };
  132. #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
  133. CPP_template(typename Rng, typename T,
  134. typename Fun)(requires copy_constructible<T> && copy_constructible<Fun>)
  135. exclusive_scan_view(Rng &&, T, Fun)
  136. ->exclusive_scan_view<views::all_t<Rng>, T, Fun>;
  137. #endif
  138. namespace views
  139. {
  140. struct exclusive_scan_fn
  141. {
  142. private:
  143. friend view_access;
  144. template<typename T, typename Fun = plus>
  145. static constexpr auto bind(exclusive_scan_fn exclusive_scan, T init,
  146. Fun fun = {})
  147. {
  148. return make_pipeable(
  149. bind_back(exclusive_scan, std::move(init), std::move(fun)));
  150. }
  151. public:
  152. template<typename Rng, typename T, typename Fun = plus>
  153. constexpr auto operator()(Rng && rng, T init, Fun fun = Fun{}) const
  154. -> CPP_ret(exclusive_scan_view<all_t<Rng>, T, Fun>)( //
  155. requires exclusive_scan_constraints<Rng, T, Fun>)
  156. {
  157. return {all(static_cast<Rng &&>(rng)), std::move(init), std::move(fun)};
  158. }
  159. };
  160. /// \relates exclusive_scan_fn
  161. /// \ingroup group-views
  162. RANGES_INLINE_VARIABLE(view<exclusive_scan_fn>, exclusive_scan)
  163. } // namespace views
  164. /// @}
  165. } // namespace ranges
  166. #endif // RANGE_V3_VIEW_EXCLUSIVE_SCAN_HPP