adjacent_difference.hpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2004
  5. // Copyright Gonzalo Brito Gadeschi 2014
  6. //
  7. // Use, modification and distribution is subject to the
  8. // Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. //
  12. // Project home: https://github.com/ericniebler/range-v3
  13. //
  14. // Implementation based on the code in libc++
  15. // http://http://libcxx.llvm.org/
  16. #ifndef RANGES_V3_NUMERIC_ADJACENT_DIFFERENCE_HPP
  17. #define RANGES_V3_NUMERIC_ADJACENT_DIFFERENCE_HPP
  18. #include <meta/meta.hpp>
  19. #include <range/v3/algorithm/result_types.hpp>
  20. #include <range/v3/functional/arithmetic.hpp>
  21. #include <range/v3/functional/identity.hpp>
  22. #include <range/v3/functional/invoke.hpp>
  23. #include <range/v3/iterator/concepts.hpp>
  24. #include <range/v3/iterator/traits.hpp>
  25. #include <range/v3/iterator/unreachable_sentinel.hpp>
  26. #include <range/v3/range/access.hpp>
  27. #include <range/v3/range/concepts.hpp>
  28. #include <range/v3/range/dangling.hpp>
  29. #include <range/v3/range/traits.hpp>
  30. #include <range/v3/utility/static_const.hpp>
  31. #include <range/v3/detail/prologue.hpp>
  32. namespace ranges
  33. {
  34. /// \addtogroup group-numerics
  35. /// @{
  36. // clang-format off
  37. /// \concept differenceable_
  38. /// \brief The \c differenceable_ concept
  39. template(typename I, typename O, typename BOp, typename P)(
  40. concept (differenceable_)(I, O, BOp, P),
  41. invocable<P&, iter_value_t<I>> AND
  42. copy_constructible<uncvref_t<invoke_result_t<P&, iter_value_t<I>>>> AND
  43. movable<uncvref_t<invoke_result_t<P&, iter_value_t<I>>>> AND
  44. output_iterator<O, invoke_result_t<P&, iter_value_t<I>>> AND
  45. invocable<
  46. BOp&,
  47. invoke_result_t<
  48. P&,
  49. iter_value_t<I>>,
  50. invoke_result_t<P&, iter_value_t<I>>> AND
  51. output_iterator<
  52. O,
  53. invoke_result_t<
  54. BOp&,
  55. invoke_result_t<P&, iter_value_t<I>>,
  56. invoke_result_t<P&, iter_value_t<I>>>>);
  57. /// \concept differenceable
  58. /// \brief The \c differenceable concept
  59. template<typename I, typename O, typename BOp = minus, typename P = identity>
  60. CPP_concept differenceable =
  61. input_iterator<I> &&
  62. CPP_concept_ref(ranges::differenceable_, I, O, BOp, P);
  63. // clang-format on
  64. template<typename I, typename O>
  65. using adjacent_difference_result = detail::in_out_result<I, O>;
  66. struct adjacent_difference_fn
  67. {
  68. template(typename I, typename S, typename O, typename S2, typename BOp = minus,
  69. typename P = identity)(
  70. requires sentinel_for<S, I> AND sentinel_for<S2, O> AND
  71. differenceable<I, O, BOp, P>)
  72. adjacent_difference_result<I, O> operator()(I first,
  73. S last,
  74. O result,
  75. S2 end_result,
  76. BOp bop = BOp{},
  77. P proj = P{}) const
  78. {
  79. // BUGBUG think about the use of coerce here.
  80. using V = iter_value_t<I>;
  81. using X = invoke_result_t<P &, V>;
  82. coerce<V> v;
  83. coerce<X> x;
  84. if(first != last && result != end_result)
  85. {
  86. auto t1(x(invoke(proj, v(*first))));
  87. *result = t1;
  88. for(++first, ++result; first != last && result != end_result;
  89. ++first, ++result)
  90. {
  91. auto t2(x(invoke(proj, v(*first))));
  92. *result = invoke(bop, t2, t1);
  93. t1 = std::move(t2);
  94. }
  95. }
  96. return {first, result};
  97. }
  98. template(typename I, typename S, typename O, typename BOp = minus,
  99. typename P = identity)(
  100. requires sentinel_for<S, I> AND differenceable<I, O, BOp, P>)
  101. adjacent_difference_result<I, O> //
  102. operator()(I first, S last, O result, BOp bop = BOp{}, P proj = P{}) const
  103. {
  104. return (*this)(std::move(first),
  105. std::move(last),
  106. std::move(result),
  107. unreachable,
  108. std::move(bop),
  109. std::move(proj));
  110. }
  111. template(typename Rng, typename ORef, typename BOp = minus, typename P = identity,
  112. typename I = iterator_t<Rng>, typename O = uncvref_t<ORef>)(
  113. requires range<Rng> AND differenceable<I, O, BOp, P>)
  114. adjacent_difference_result<borrowed_iterator_t<Rng>, O> //
  115. operator()(Rng && rng, ORef && result, BOp bop = BOp{}, P proj = P{}) const
  116. {
  117. return (*this)(begin(rng),
  118. end(rng),
  119. static_cast<ORef &&>(result),
  120. std::move(bop),
  121. std::move(proj));
  122. }
  123. template(typename Rng, typename ORng, typename BOp = minus, typename P = identity,
  124. typename I = iterator_t<Rng>, typename O = iterator_t<ORng>)(
  125. requires range<Rng> AND range<ORng> AND differenceable<I, O, BOp, P>)
  126. adjacent_difference_result<borrowed_iterator_t<Rng>, borrowed_iterator_t<ORng>>
  127. operator()(Rng && rng, ORng && result, BOp bop = BOp{}, P proj = P{}) const
  128. {
  129. return (*this)(begin(rng),
  130. end(rng),
  131. begin(result),
  132. end(result),
  133. std::move(bop),
  134. std::move(proj));
  135. }
  136. };
  137. RANGES_INLINE_VARIABLE(adjacent_difference_fn, adjacent_difference)
  138. /// @}
  139. } // namespace ranges
  140. #include <range/v3/detail/epilogue.hpp>
  141. #endif