File indexing completed on 2025-12-16 10:27:53
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #ifndef RANGES_V3_ALGORITHM_INPLACE_MERGE_HPP
0022 #define RANGES_V3_ALGORITHM_INPLACE_MERGE_HPP
0023
0024 #include <functional>
0025 #include <memory>
0026 #include <new>
0027 #include <type_traits>
0028
0029 #include <range/v3/range_fwd.hpp>
0030
0031 #include <range/v3/algorithm/lower_bound.hpp>
0032 #include <range/v3/algorithm/merge.hpp>
0033 #include <range/v3/algorithm/min.hpp>
0034 #include <range/v3/algorithm/move.hpp>
0035 #include <range/v3/algorithm/rotate.hpp>
0036 #include <range/v3/algorithm/upper_bound.hpp>
0037 #include <range/v3/functional/comparisons.hpp>
0038 #include <range/v3/functional/identity.hpp>
0039 #include <range/v3/functional/invoke.hpp>
0040 #include <range/v3/functional/not_fn.hpp>
0041 #include <range/v3/iterator/concepts.hpp>
0042 #include <range/v3/iterator/move_iterators.hpp>
0043 #include <range/v3/iterator/operations.hpp>
0044 #include <range/v3/iterator/reverse_iterator.hpp>
0045 #include <range/v3/iterator/traits.hpp>
0046 #include <range/v3/range/access.hpp>
0047 #include <range/v3/range/concepts.hpp>
0048 #include <range/v3/range/dangling.hpp>
0049 #include <range/v3/range/traits.hpp>
0050 #include <range/v3/utility/memory.hpp>
0051 #include <range/v3/utility/static_const.hpp>
0052 #include <range/v3/utility/swap.hpp>
0053
0054 #include <range/v3/detail/prologue.hpp>
0055
0056 namespace ranges
0057 {
0058
0059 namespace detail
0060 {
0061 struct merge_adaptive_fn
0062 {
0063 private:
0064 template<typename I, typename C, typename P>
0065 static void impl(I first, I middle, I last, iter_difference_t<I> len1,
0066 iter_difference_t<I> len2, iter_value_t<I> * const buf,
0067 C & pred, P & proj)
0068 {
0069 auto tmpbuf = make_raw_buffer(buf);
0070 if(len1 <= len2)
0071 {
0072 auto p = ranges::move(first, middle, tmpbuf.begin()).out;
0073 merge(make_move_iterator(buf),
0074 make_move_iterator(p.base().base()),
0075 make_move_iterator(std::move(middle)),
0076 make_move_iterator(std::move(last)),
0077 std::move(first),
0078 std::ref(pred),
0079 std::ref(proj),
0080 std::ref(proj));
0081 }
0082 else
0083 {
0084 auto p = ranges::move(middle, last, tmpbuf.begin()).out;
0085 using RBi = ranges::reverse_iterator<I>;
0086 using Rv = ranges::reverse_iterator<iter_value_t<I> *>;
0087 merge(make_move_iterator(RBi{std::move(middle)}),
0088 make_move_iterator(RBi{std::move(first)}),
0089 make_move_iterator(Rv{p.base().base()}),
0090 make_move_iterator(Rv{buf}),
0091 RBi{std::move(last)},
0092 not_fn(std::ref(pred)),
0093 std::ref(proj),
0094 std::ref(proj));
0095 }
0096 }
0097
0098 public:
0099 template(typename I, typename C = less, typename P = identity)(
0100 requires bidirectional_iterator<I> AND sortable<I, C, P>)
0101 void operator()(I first, I middle, I last, iter_difference_t<I> len1,
0102 iter_difference_t<I> len2, iter_value_t<I> * buf,
0103 std::ptrdiff_t buf_size, C pred = C{}, P proj = P{}) const
0104 {
0105 using D = iter_difference_t<I>;
0106 while(true)
0107 {
0108
0109 if(len2 == 0)
0110 return;
0111
0112
0113 for(; true; ++first, --len1)
0114 {
0115 if(len1 == 0)
0116 return;
0117 if(invoke(pred, invoke(proj, *middle), invoke(proj, *first)))
0118 break;
0119 }
0120 if(len1 <= buf_size || len2 <= buf_size)
0121 {
0122 merge_adaptive_fn::impl(std::move(first),
0123 std::move(middle),
0124 std::move(last),
0125 len1,
0126 len2,
0127 buf,
0128 pred,
0129 proj);
0130 return;
0131 }
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141 I m1;
0142 I m2;
0143 D len11;
0144 D len21;
0145
0146 if(len1 < len2)
0147 {
0148 len21 = len2 / 2;
0149 m2 = next(middle, len21);
0150 m1 = upper_bound(first,
0151 middle,
0152 invoke(proj, *m2),
0153 std::ref(pred),
0154 std::ref(proj));
0155 len11 = distance(first, m1);
0156 }
0157 else
0158 {
0159 if(len1 == 1)
0160 {
0161
0162 ranges::iter_swap(first, middle);
0163 return;
0164 }
0165
0166 len11 = len1 / 2;
0167 m1 = next(first, len11);
0168 m2 = lower_bound(middle,
0169 last,
0170 invoke(proj, *m1),
0171 std::ref(pred),
0172 std::ref(proj));
0173 len21 = distance(middle, m2);
0174 }
0175 D len12 = len1 - len11;
0176 D len22 = len2 - len21;
0177
0178
0179 middle = rotate(m1, std::move(middle), m2).begin();
0180
0181
0182
0183 if(len11 + len21 < len12 + len22)
0184 {
0185 (*this)(std::move(first),
0186 std::move(m1),
0187 middle,
0188 len11,
0189 len21,
0190 buf,
0191 buf_size,
0192 std::ref(pred),
0193 std::ref(proj));
0194 first = std::move(middle);
0195 middle = std::move(m2);
0196 len1 = len12;
0197 len2 = len22;
0198 }
0199 else
0200 {
0201 (*this)(middle,
0202 std::move(m2),
0203 std::move(last),
0204 len12,
0205 len22,
0206 buf,
0207 buf_size,
0208 std::ref(pred),
0209 std::ref(proj));
0210 last = std::move(middle);
0211 middle = std::move(m1);
0212 len1 = len11;
0213 len2 = len21;
0214 }
0215 }
0216 }
0217 };
0218
0219 RANGES_INLINE_VARIABLE(merge_adaptive_fn, merge_adaptive)
0220
0221 struct inplace_merge_no_buffer_fn
0222 {
0223 template(typename I, typename C = less, typename P = identity)(
0224 requires bidirectional_iterator<I> AND sortable<I, C, P>)
0225 void operator()(I first, I middle, I last, iter_difference_t<I> len1,
0226 iter_difference_t<I> len2, C pred = C{}, P proj = P{}) const
0227 {
0228 merge_adaptive(std::move(first),
0229 std::move(middle),
0230 std::move(last),
0231 len1,
0232 len2,
0233 static_cast<iter_value_t<I> *>(nullptr),
0234 0,
0235 std::move(pred),
0236 std::move(proj));
0237 }
0238 };
0239
0240 RANGES_INLINE_VARIABLE(inplace_merge_no_buffer_fn, inplace_merge_no_buffer)
0241 }
0242
0243
0244
0245
0246 RANGES_FUNC_BEGIN(inplace_merge)
0247
0248
0249
0250
0251 template(typename I, typename S, typename C = less, typename P = identity)(
0252 requires bidirectional_iterator<I> AND sortable<I, C, P>)
0253 I RANGES_FUNC(inplace_merge)(
0254 I first, I middle, S last, C pred = C{}, P proj = P{})
0255 {
0256 using value_type = iter_value_t<I>;
0257 auto len1 = distance(first, middle);
0258 auto len2_and_end = enumerate(middle, last);
0259 auto buf_size = ranges::min(len1, len2_and_end.first);
0260 std::pair<value_type *, std::ptrdiff_t> buf{nullptr, 0};
0261 std::unique_ptr<value_type, detail::return_temporary_buffer> h;
0262 if(detail::is_trivially_copy_assignable_v<value_type> && 8 < buf_size)
0263 {
0264 buf = detail::get_temporary_buffer<value_type>(buf_size);
0265 h.reset(buf.first);
0266 }
0267 detail::merge_adaptive(std::move(first),
0268 std::move(middle),
0269 len2_and_end.second,
0270 len1,
0271 len2_and_end.first,
0272 buf.first,
0273 buf.second,
0274 std::move(pred),
0275 std::move(proj));
0276 return len2_and_end.second;
0277 }
0278
0279
0280 template(typename Rng, typename C = less, typename P = identity)(
0281 requires bidirectional_range<Rng> AND sortable<iterator_t<Rng>, C, P>)
0282 borrowed_iterator_t<Rng> RANGES_FUNC(inplace_merge)(
0283 Rng && rng, iterator_t<Rng> middle, C pred = C{}, P proj = P{})
0284 {
0285 return (*this)(begin(rng),
0286 std::move(middle),
0287 end(rng),
0288 std::move(pred),
0289 std::move(proj));
0290 }
0291
0292 RANGES_FUNC_END(inplace_merge)
0293
0294 namespace cpp20
0295 {
0296 using ranges::inplace_merge;
0297 }
0298
0299 }
0300
0301 #include <range/v3/detail/epilogue.hpp>
0302
0303 #endif