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.

137 lines
4.5KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2014-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. //===-------------------------- algorithm ---------------------------------===//
  14. //
  15. // The LLVM Compiler Infrastructure
  16. //
  17. // This file is dual licensed under the MIT and the University of Illinois Open
  18. // Source Licenses. See LICENSE.TXT for details.
  19. //
  20. //===----------------------------------------------------------------------===//
  21. #ifndef RANGES_V3_ALGORITHM_PARTITION_HPP
  22. #define RANGES_V3_ALGORITHM_PARTITION_HPP
  23. #include <meta/meta.hpp>
  24. #include <range/v3/range_fwd.hpp>
  25. #include <range/v3/functional/identity.hpp>
  26. #include <range/v3/functional/invoke.hpp>
  27. #include <range/v3/iterator/concepts.hpp>
  28. #include <range/v3/iterator/operations.hpp>
  29. #include <range/v3/iterator/traits.hpp>
  30. #include <range/v3/range/access.hpp>
  31. #include <range/v3/range/concepts.hpp>
  32. #include <range/v3/range/dangling.hpp>
  33. #include <range/v3/range/traits.hpp>
  34. #include <range/v3/utility/static_const.hpp>
  35. #include <range/v3/utility/swap.hpp>
  36. namespace ranges
  37. {
  38. /// \addtogroup group-algorithms
  39. /// @{
  40. /// \cond
  41. namespace detail
  42. {
  43. template<typename I, typename S, typename C, typename P>
  44. I partition_impl(I first, S last, C pred, P proj, detail::forward_iterator_tag_)
  45. {
  46. while(true)
  47. {
  48. if(first == last)
  49. return first;
  50. if(!invoke(pred, invoke(proj, *first)))
  51. break;
  52. ++first;
  53. }
  54. for(I p = first; ++p != last;)
  55. {
  56. if(invoke(pred, invoke(proj, *p)))
  57. {
  58. ranges::iter_swap(first, p);
  59. ++first;
  60. }
  61. }
  62. return first;
  63. }
  64. template<typename I, typename S, typename C, typename P>
  65. I partition_impl(I first, S end_, C pred, P proj,
  66. detail::bidirectional_iterator_tag_)
  67. {
  68. I last = ranges::next(first, end_);
  69. while(true)
  70. {
  71. while(true)
  72. {
  73. if(first == last)
  74. return first;
  75. if(!invoke(pred, invoke(proj, *first)))
  76. break;
  77. ++first;
  78. }
  79. do
  80. {
  81. if(first == --last)
  82. return first;
  83. } while(!invoke(pred, invoke(proj, *last)));
  84. ranges::iter_swap(first, last);
  85. ++first;
  86. }
  87. }
  88. } // namespace detail
  89. /// \endcond
  90. RANGES_BEGIN_NIEBLOID(partition)
  91. /// \brief function template \c partition
  92. template<typename I, typename S, typename C, typename P = identity>
  93. auto RANGES_FUN_NIEBLOID(partition)(I first, S last, C pred, P proj = P{}) //
  94. ->CPP_ret(I)( //
  95. requires permutable<I> && sentinel_for<S, I> &&
  96. indirect_unary_predicate<C, projected<I, P>>)
  97. {
  98. return detail::partition_impl(std::move(first),
  99. std::move(last),
  100. std::move(pred),
  101. std::move(proj),
  102. iterator_tag_of<I>());
  103. }
  104. /// \overload
  105. template<typename Rng, typename C, typename P = identity>
  106. auto RANGES_FUN_NIEBLOID(partition)(Rng && rng, C pred, P proj = P{}) //
  107. ->CPP_ret(safe_iterator_t<Rng>)( //
  108. requires forward_range<Rng> && permutable<iterator_t<Rng>> &&
  109. indirect_unary_predicate<C, projected<iterator_t<Rng>, P>>)
  110. {
  111. return detail::partition_impl(begin(rng),
  112. end(rng),
  113. std::move(pred),
  114. std::move(proj),
  115. iterator_tag_of<iterator_t<Rng>>());
  116. }
  117. RANGES_END_NIEBLOID(partition)
  118. namespace cpp20
  119. {
  120. using ranges::partition;
  121. }
  122. /// @}
  123. } // namespace ranges
  124. #endif // include guard