You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
4.6KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2014-present
  5. // Copyright Casey Carter 2016
  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. #ifndef RANGES_V3_ALGORITHM_EQUAL_RANGE_HPP
  15. #define RANGES_V3_ALGORITHM_EQUAL_RANGE_HPP
  16. #include <range/v3/range_fwd.hpp>
  17. #include <range/v3/algorithm/aux_/equal_range_n.hpp>
  18. #include <range/v3/algorithm/aux_/lower_bound_n.hpp>
  19. #include <range/v3/algorithm/upper_bound.hpp>
  20. #include <range/v3/functional/comparisons.hpp>
  21. #include <range/v3/functional/identity.hpp>
  22. #include <range/v3/functional/invoke.hpp>
  23. #include <range/v3/iterator/operations.hpp>
  24. #include <range/v3/range/access.hpp>
  25. #include <range/v3/range/concepts.hpp>
  26. #include <range/v3/range/traits.hpp>
  27. #include <range/v3/utility/static_const.hpp>
  28. #include <range/v3/view/subrange.hpp>
  29. namespace ranges
  30. {
  31. /// \addtogroup group-algorithms
  32. /// @{
  33. RANGES_BEGIN_NIEBLOID(equal_range)
  34. /// \brief function template \c equal_range
  35. template<typename I,
  36. typename S,
  37. typename V,
  38. typename C = less,
  39. typename P = identity>
  40. auto RANGES_FUN_NIEBLOID(equal_range)(
  41. I first, S last, V const & val, C pred = C{}, P proj = P{})
  42. ->CPP_ret(subrange<I>)( //
  43. requires forward_iterator<I> && sentinel_for<S, I> &&
  44. indirect_strict_weak_order<C, V const *, projected<I, P>>)
  45. {
  46. if(RANGES_CONSTEXPR_IF(sized_sentinel_for<S, I>))
  47. {
  48. auto const len = distance(first, last);
  49. return aux::equal_range_n(
  50. std::move(first), len, val, std::move(pred), std::move(proj));
  51. }
  52. // Probe exponentially for either end-of-range, an iterator that
  53. // is past the equal range (i.e., denotes an element greater
  54. // than val), or is in the equal range (denotes an element equal
  55. // to val).
  56. auto dist = iter_difference_t<I>{1};
  57. while(true)
  58. {
  59. auto mid = first;
  60. auto d = advance(mid, dist, last);
  61. if(d || mid == last)
  62. {
  63. // at the end of the input range
  64. dist -= d;
  65. return aux::equal_range_n(
  66. std::move(first), dist, val, std::ref(pred), std::ref(proj));
  67. }
  68. // if val < *mid, mid is after the target range.
  69. auto && v = *mid;
  70. auto && pv = invoke(proj, (decltype(v) &&)v);
  71. if(invoke(pred, val, pv))
  72. {
  73. return aux::equal_range_n(
  74. std::move(first), dist, val, std::ref(pred), std::ref(proj));
  75. }
  76. else if(!invoke(pred, pv, val))
  77. {
  78. // *mid == val: the lower bound is <= mid, and the upper bound is >
  79. // mid.
  80. return {
  81. aux::lower_bound_n(
  82. std::move(first), dist, val, std::ref(pred), std::ref(proj)),
  83. upper_bound(std::move(mid),
  84. std::move(last),
  85. val,
  86. std::ref(pred),
  87. std::ref(proj))};
  88. }
  89. // *mid < val, mid is before the target range.
  90. first = std::move(mid);
  91. ++first;
  92. dist *= 2;
  93. }
  94. }
  95. /// \overload
  96. template<typename Rng, typename V, typename C = less, typename P = identity>
  97. auto RANGES_FUN_NIEBLOID(equal_range)(
  98. Rng && rng, V const & val, C pred = C{}, P proj = P{}) //
  99. ->CPP_ret(safe_subrange_t<Rng>)( //
  100. requires forward_range<Rng> &&
  101. indirect_strict_weak_order<C, V const *, projected<iterator_t<Rng>, P>>)
  102. {
  103. if(RANGES_CONSTEXPR_IF(sized_range<Rng>))
  104. {
  105. auto const len = distance(rng);
  106. return aux::equal_range_n(
  107. begin(rng), len, val, std::move(pred), std::move(proj));
  108. }
  109. return (*this)(begin(rng), end(rng), val, std::move(pred), std::move(proj));
  110. }
  111. RANGES_END_NIEBLOID(equal_range)
  112. namespace cpp20
  113. {
  114. using ranges::equal_range;
  115. }
  116. /// @}
  117. } // namespace ranges
  118. #endif // include guard