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.

inplace_merge.hpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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. //===----------------------------------------------------------------------===//
  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_INPLACE_MERGE_HPP
  22. #define RANGES_V3_ALGORITHM_INPLACE_MERGE_HPP
  23. #include <functional>
  24. #include <memory>
  25. #include <new>
  26. #include <type_traits>
  27. #include <range/v3/range_fwd.hpp>
  28. #include <range/v3/algorithm/lower_bound.hpp>
  29. #include <range/v3/algorithm/merge.hpp>
  30. #include <range/v3/algorithm/min.hpp>
  31. #include <range/v3/algorithm/move.hpp>
  32. #include <range/v3/algorithm/rotate.hpp>
  33. #include <range/v3/algorithm/upper_bound.hpp>
  34. #include <range/v3/functional/comparisons.hpp>
  35. #include <range/v3/functional/identity.hpp>
  36. #include <range/v3/functional/invoke.hpp>
  37. #include <range/v3/functional/not_fn.hpp>
  38. #include <range/v3/iterator/concepts.hpp>
  39. #include <range/v3/iterator/move_iterators.hpp>
  40. #include <range/v3/iterator/operations.hpp>
  41. #include <range/v3/iterator/reverse_iterator.hpp>
  42. #include <range/v3/iterator/traits.hpp>
  43. #include <range/v3/range/access.hpp>
  44. #include <range/v3/range/concepts.hpp>
  45. #include <range/v3/range/dangling.hpp>
  46. #include <range/v3/range/traits.hpp>
  47. #include <range/v3/utility/memory.hpp>
  48. #include <range/v3/utility/static_const.hpp>
  49. #include <range/v3/utility/swap.hpp>
  50. namespace ranges
  51. {
  52. /// \cond
  53. namespace detail
  54. {
  55. struct merge_adaptive_fn
  56. {
  57. private:
  58. template<typename I, typename C, typename P>
  59. static void impl(I first, I middle, I last, iter_difference_t<I> len1,
  60. iter_difference_t<I> len2, iter_value_t<I> * const buf,
  61. C & pred, P & proj)
  62. {
  63. auto tmpbuf = make_raw_buffer(buf);
  64. if(len1 <= len2)
  65. {
  66. auto p = ranges::move(first, middle, tmpbuf.begin()).out;
  67. merge(make_move_iterator(buf),
  68. make_move_iterator(p.base().base()),
  69. make_move_iterator(std::move(middle)),
  70. make_move_iterator(std::move(last)),
  71. std::move(first),
  72. std::ref(pred),
  73. std::ref(proj),
  74. std::ref(proj));
  75. }
  76. else
  77. {
  78. auto p = ranges::move(middle, last, tmpbuf.begin()).out;
  79. using RBi = ranges::reverse_iterator<I>;
  80. using Rv = ranges::reverse_iterator<iter_value_t<I> *>;
  81. merge(make_move_iterator(RBi{std::move(middle)}),
  82. make_move_iterator(RBi{std::move(first)}),
  83. make_move_iterator(Rv{p.base().base()}),
  84. make_move_iterator(Rv{buf}),
  85. RBi{std::move(last)},
  86. not_fn(std::ref(pred)),
  87. std::ref(proj),
  88. std::ref(proj));
  89. }
  90. }
  91. public:
  92. template<typename I, typename C = less, typename P = identity>
  93. auto operator()(I first, I middle, I last, iter_difference_t<I> len1,
  94. iter_difference_t<I> len2, iter_value_t<I> * buf,
  95. std::ptrdiff_t buf_size, C pred = C{}, P proj = P{}) const
  96. -> CPP_ret(void)( //
  97. requires bidirectional_iterator<I> && sortable<I, C, P>)
  98. {
  99. using D = iter_difference_t<I>;
  100. while(true)
  101. {
  102. // if middle == last, we're done
  103. if(len2 == 0)
  104. return;
  105. // shrink [first, middle) as much as possible (with no moves),
  106. // returning if it shrinks to 0
  107. for(; true; ++first, --len1)
  108. {
  109. if(len1 == 0)
  110. return;
  111. if(invoke(pred, invoke(proj, *middle), invoke(proj, *first)))
  112. break;
  113. }
  114. if(len1 <= buf_size || len2 <= buf_size)
  115. {
  116. merge_adaptive_fn::impl(std::move(first),
  117. std::move(middle),
  118. std::move(last),
  119. len1,
  120. len2,
  121. buf,
  122. pred,
  123. proj);
  124. return;
  125. }
  126. // first < middle < end
  127. // *first > *middle
  128. // partition [first, m1) [m1, middle) [middle, m2) [m2, last) such
  129. // that
  130. // all elements in:
  131. // [first, m1) <= [middle, m2)
  132. // [middle, m2) < [m1, middle)
  133. // [m1, middle) <= [m2, last)
  134. // and m1 or m2 is in the middle of its range
  135. I m1; // "median" of [first, middle)
  136. I m2; // "median" of [middle, last)
  137. D len11; // distance(first, m1)
  138. D len21; // distance(middle, m2)
  139. // binary search smaller range
  140. if(len1 < len2)
  141. { // len >= 1, len2 >= 2
  142. len21 = len2 / 2;
  143. m2 = next(middle, len21);
  144. m1 = upper_bound(first,
  145. middle,
  146. invoke(proj, *m2),
  147. std::ref(pred),
  148. std::ref(proj));
  149. len11 = distance(first, m1);
  150. }
  151. else
  152. {
  153. if(len1 == 1)
  154. { // len1 >= len2 && len2 > 0, therefore len2 == 1
  155. // It is known *first > *middle
  156. ranges::iter_swap(first, middle);
  157. return;
  158. }
  159. // len1 >= 2, len2 >= 1
  160. len11 = len1 / 2;
  161. m1 = next(first, len11);
  162. m2 = lower_bound(middle,
  163. last,
  164. invoke(proj, *m1),
  165. std::ref(pred),
  166. std::ref(proj));
  167. len21 = distance(middle, m2);
  168. }
  169. D len12 = len1 - len11; // distance(m1, middle)
  170. D len22 = len2 - len21; // distance(m2, last)
  171. // [first, m1) [m1, middle) [middle, m2) [m2, last)
  172. // swap middle two partitions
  173. middle = rotate(m1, std::move(middle), m2).begin();
  174. // len12 and len21 now have swapped meanings
  175. // merge smaller range with recursive call and larger with tail
  176. // recursion elimination
  177. if(len11 + len21 < len12 + len22)
  178. {
  179. (*this)(std::move(first),
  180. std::move(m1),
  181. middle,
  182. len11,
  183. len21,
  184. buf,
  185. buf_size,
  186. std::ref(pred),
  187. std::ref(proj));
  188. first = std::move(middle);
  189. middle = std::move(m2);
  190. len1 = len12;
  191. len2 = len22;
  192. }
  193. else
  194. {
  195. (*this)(middle,
  196. std::move(m2),
  197. std::move(last),
  198. len12,
  199. len22,
  200. buf,
  201. buf_size,
  202. std::ref(pred),
  203. std::ref(proj));
  204. last = std::move(middle);
  205. middle = std::move(m1);
  206. len1 = len11;
  207. len2 = len21;
  208. }
  209. }
  210. }
  211. };
  212. RANGES_INLINE_VARIABLE(merge_adaptive_fn, merge_adaptive)
  213. struct inplace_merge_no_buffer_fn
  214. {
  215. template<typename I, typename C = less, typename P = identity>
  216. auto operator()(I first, I middle, I last, iter_difference_t<I> len1,
  217. iter_difference_t<I> len2, C pred = C{}, P proj = P{}) const
  218. -> CPP_ret(void)( //
  219. requires bidirectional_iterator<I> && sortable<I, C, P>)
  220. {
  221. merge_adaptive(std::move(first),
  222. std::move(middle),
  223. std::move(last),
  224. len1,
  225. len2,
  226. static_cast<iter_value_t<I> *>(nullptr),
  227. 0,
  228. std::move(pred),
  229. std::move(proj));
  230. }
  231. };
  232. RANGES_INLINE_VARIABLE(inplace_merge_no_buffer_fn, inplace_merge_no_buffer)
  233. } // namespace detail
  234. /// \endcond
  235. /// \addtogroup group-algorithms
  236. /// @{
  237. RANGES_BEGIN_NIEBLOID(inplace_merge)
  238. // TODO reimplement to only need forward iterators
  239. /// \brief function template \c inplace_merge
  240. template<typename I, typename S, typename C = less, typename P = identity>
  241. auto RANGES_FUN_NIEBLOID(inplace_merge)(
  242. I first, I middle, S last, C pred = C{}, P proj = P{})
  243. ->CPP_ret(I)( //
  244. requires bidirectional_iterator<I> && sortable<I, C, P>)
  245. {
  246. using value_type = iter_value_t<I>;
  247. auto len1 = distance(first, middle);
  248. auto len2_and_end = enumerate(middle, last);
  249. auto buf_size = ranges::min(len1, len2_and_end.first);
  250. std::pair<value_type *, std::ptrdiff_t> buf{nullptr, 0};
  251. std::unique_ptr<value_type, detail::return_temporary_buffer> h;
  252. if(detail::is_trivially_copy_assignable<value_type>::value && 8 < buf_size)
  253. {
  254. buf = detail::get_temporary_buffer<value_type>(buf_size);
  255. h.reset(buf.first);
  256. }
  257. detail::merge_adaptive(std::move(first),
  258. std::move(middle),
  259. len2_and_end.second,
  260. len1,
  261. len2_and_end.first,
  262. buf.first,
  263. buf.second,
  264. std::move(pred),
  265. std::move(proj));
  266. return len2_and_end.second;
  267. }
  268. /// \overload
  269. template<typename Rng, typename C = less, typename P = identity>
  270. auto RANGES_FUN_NIEBLOID(inplace_merge)(
  271. Rng && rng, iterator_t<Rng> middle, C pred = C{}, P proj = P{})
  272. ->CPP_ret(safe_iterator_t<Rng>)( //
  273. requires bidirectional_range<Rng> && sortable<iterator_t<Rng>, C, P>)
  274. {
  275. return (*this)(begin(rng),
  276. std::move(middle),
  277. end(rng),
  278. std::move(pred),
  279. std::move(proj));
  280. }
  281. RANGES_END_NIEBLOID(inplace_merge)
  282. namespace cpp20
  283. {
  284. using ranges::inplace_merge;
  285. }
  286. /// @}
  287. } // namespace ranges
  288. #endif // include guard