static range<I> rotate_gcd(I begin, I middle, I end) { auto const m1 = middle - begin; auto const m2 = end - middle; if(m1 == m2) { swap_ranges(begin, middle, middle); return {middle, end}; } auto const g = rotate_fn::gcd(m1, m2); for (I p = begin + g; p != begin;) { iterator_value_t<I> t = iter_move(--p); I p1 = p; I p2 = p1 + m1; do { *p1 = iter_move(p2); p1 = p2; auto const d = end - p2; if(m1 < d) p2 += m1; else p2 = begin + (m1 - d); } while(p2 != p); *p1 = std::move(t); } return {begin + m2, end}; }
friend iterator_rvalue_reference_t<I> indirect_move(common_iterator<I, S> const &it) noexcept(noexcept(iter_move(std::declval<I const &>()))) { common_cursor const &cur = get_cursor(it); RANGES_ASSERT(!cur.is_sentinel()); return iter_move(cur.it()); }
static I impl(I begin, I end, C pred, P proj, D len, Pair p, concepts::ForwardIterator *fi) { // *begin is known to be false // len >= 1 if (len == 1) return begin; if(len == 2) { I tmp = begin; if(pred(proj(*++tmp))) { ranges::iter_swap(begin, tmp); return tmp; } return begin; } if(len <= p.second) { // The buffer is big enough to use using value_type = iterator_value_t<I>; std::unique_ptr<value_type, detail::destroy_n<value_type>> h{p.first, {}}; // Move the falses into the temporary buffer, and the trues to the front of the line // Update begin to always point to the end of the trues auto buf = ranges::make_counted_raw_storage_iterator(p.first, h.get_deleter()); *buf = iter_move(begin); ++buf; auto res = partition_move(next(begin), end, begin, buf, std::ref(pred), std::ref(proj)); // All trues now at start of range, all falses in buffer // Move falses back into range, but don't mess up begin which points to first false ranges::move(p.first, std::get<2>(res).base().base(), std::get<1>(res)); // h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer return std::get<1>(res); } // Else not enough buffer, do in place // len >= 3 D half = len / 2; // half >= 2 I middle = next(begin, half); // recurse on [begin, middle), *begin know to be false // F????????????????? // f m l I begin_false = stable_partition_fn::impl(begin, middle, pred, proj, half, p, fi); // TTTFFFFF?????????? // f ff m l // recurse on [middle, end], except increase middle until *(middle) is false, *end know to be true I m1 = middle; D len_half = len - half; while(pred(proj(*m1))) { if(++m1 == end) return ranges::rotate(begin_false, middle, end).begin(); --len_half; } // TTTFFFFFTTTF?????? // f ff m m1 l I end_false = stable_partition_fn::impl(m1, end, pred, proj, len_half, p, fi); // TTTFFFFFTTTTTFFFFF // f ff m sf l return ranges::rotate(begin_false, middle, end_false).begin(); // TTTTTTTTFFFFFFFFFF // | }
static range<I> rotate_left(I begin, I end) { iterator_value_t<I> tmp = iter_move(begin); I lm1 = move(next(begin), end, begin).second; *lm1 = std::move(tmp); return {lm1, end}; }
static I impl(I begin, I end, C pred, P proj, D len, Pair const p, concepts::ForwardIterator *fi) { // *begin is known to be false // len >= 1 if(len == 1) return begin; if(len == 2) { I tmp = begin; if(invoke(pred, invoke(proj, *++tmp))) { ranges::iter_swap(begin, tmp); return tmp; } return begin; } if(len <= p.second) { // The buffer is big enough to use // Move the falses into the temporary buffer, and the trues to the front of the line // Update begin to always point to the end of the trues auto tmpbuf = make_raw_buffer(p.first); auto buf = tmpbuf.begin(); *buf = iter_move(begin); ++buf; auto res = partition_copy(make_move_iterator(next(begin)), make_move_sentinel(end), begin, buf, std::ref(pred), std::ref(proj)); // All trues now at start of range, all falses in buffer // Move falses back into range, but don't mess up begin which points to first false ranges::move(p.first, res.out2().base().base(), res.out1()); // h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer return res.out1(); } // Else not enough buffer, do in place // len >= 3 D half = len / 2; // half >= 2 I middle = next(begin, half); // recurse on [begin, middle), *begin know to be false // F????????????????? // f m l I begin_false = stable_partition_fn::impl(begin, middle, pred, proj, half, p, fi); // TTTFFFFF?????????? // f ff m l // recurse on [middle, end], except increase middle until *(middle) is false, *end know to be true I m1 = middle; D len_half = len - half; while(invoke(pred, invoke(proj, *m1))) { if(++m1 == end) return ranges::rotate(begin_false, middle, end).begin(); --len_half; } // TTTFFFFFTTTF?????? // f ff m m1 l I end_false = stable_partition_fn::impl(m1, end, pred, proj, len_half, p, fi); // TTTFFFFFTTTTTFFFFF // f ff m sf l return ranges::rotate(begin_false, middle, end_false).begin(); // TTTTTTTTFFFFFFFFFF // | }
static range<I> rotate_right(I begin, I end) { I lm1 = prev(end); iterator_value_t<I> tmp = iter_move(lm1); I fp1 = move_backward(begin, lm1, end).second; *begin = std::move(tmp); return {fp1, end}; }
common_reference_t<unwrap_reference_t<Val2 const &>, rvalue_reference_t<I>> operator()(move_tag, I const &i) const { auto &&x = iter_move(i); if(x == unwrap_reference(old_value_)) return unwrap_reference(new_value_); return ((decltype(x) &&) x); }
inline void linear_insert(I begin, I end, C &pred, P &proj) { iterator_value_t<I> val = iter_move(end); if(pred(proj(val), proj(*begin))) { move_backward(begin, end, end + 1); *begin = std::move(val); } else detail::unguarded_linear_insert(end, std::move(val), pred, proj); }
inline void unguarded_linear_insert(I end, iterator_value_t<I> val, C &pred, P &proj) { I next = prev(end); while(pred(proj(val), proj(*next))) { *end = iter_move(next); end = next; --next; } *end = std::move(val); }
std::pair<I, O> operator()(I begin, S end_, O out, P proj_ = P{}) const { auto &&proj = invokable(proj_); I i = next_to(begin, end_), end = i; while(begin != i) { // BUGBUG should the projection be applied *before* the move? auto &&x = iter_move(--i); *--out = proj((decltype(x) &&) x); } return {end, out}; }
I operator()(I begin, S end, C pred = C{}, P proj = P{}) const { begin = adjacent_find(std::move(begin), end, std::ref(pred), std::ref(proj)); if(begin != end) { for(I i = next(begin); ++i != end;) if(!invoke(pred, invoke(proj, *begin), invoke(proj, *i))) *++begin = iter_move(i); ++begin; } return begin; }
std::tuple<I0, I1, O> operator()(I0 begin0, S0 end0, I1 begin1, S1 end1, O out, C pred_ = C{}, P0 proj0_ = P0{}, P1 proj1_ = P1{}) const { auto &&pred = as_function(pred_); auto &&proj0 = as_function(proj0_); auto &&proj1 = as_function(proj1_); for(; begin0 != end0 && begin1 != end1; ++out) { if(pred(proj1(*begin1), proj0(*begin0))) { *out = iter_move(begin1); ++begin1; } else { *out = iter_move(begin0); ++begin0; } } auto t0 = move(begin0, end0, out); auto t1 = move(begin1, end1, t0.second); return std::tuple<I0, I1, O>{t0.first, t1.first, t1.second}; }
I operator()(I begin, S end, C pred_ = C{}, P proj_ = P{}) const { auto &&pred = as_function(pred_); auto &&proj = as_function(proj_); begin = adjacent_find(std::move(begin), end, std::ref(pred), std::ref(proj)); if(begin != end) { for(I i = next(begin); ++i != end;) if(!pred(proj(*begin), proj(*i))) *++begin = iter_move(i); ++begin; } return begin; }
I operator()(I first, S last, C pred, P proj = {}) const { while(true) { first = find_if(std::move(first), last, pred, proj); last = find_if_not( make_reverse_iterator(std::move(last)), make_reverse_iterator(first), pred, proj).base(); if (first == last) return first; *first = iter_move(--last); // discussion here: https://github.com/ericniebler/range-v3/issues/988 ++first; } }
I operator()(I begin, S end, T const &val, P proj_ = P{}) const { auto &&proj = as_function(proj_); begin = find(std::move(begin), end, val, std::ref(proj)); if(begin != end) { for(I i = next(begin); i != end; ++i) { if(!(proj(*i) == val)) { *begin = iter_move(i); ++begin; } } } return begin; }
I operator()(I begin, S end, C pred_, P proj_ = P{}) const { auto &&pred = as_function(pred_); auto &&proj = as_function(proj_); begin = find_if(std::move(begin), end, std::ref(pred), std::ref(proj)); if(begin != end) { for(I i = next(begin); i != end; ++i) { if(!(pred(proj(*i)))) { *begin = iter_move(i); ++begin; } } } return begin; }
auto operator()(Its const &...its) const noexcept(meta::and_c<noexcept(iterator_reference_t<Its>(*its))...>::value) RANGES_DECLTYPE_AUTO_RETURN ( common_tuple<iterator_reference_t<Its>...>{*its...} ) // tuple rvalue reference template<typename ...Its, CONCEPT_REQUIRES_(meta::and_<Readable<Its>...>() && sizeof...(Its) != 2)> auto operator()(move_tag, Its const &...its) const noexcept(meta::and_c< noexcept(iterator_rvalue_reference_t<Its>(iter_move(its)))...>::value) RANGES_DECLTYPE_AUTO_RETURN ( common_tuple<iterator_rvalue_reference_t<Its>...>{iter_move(its)...} ) // pair value template<typename It1, typename It2, CONCEPT_REQUIRES_(Readable<It1>() && Readable<It2>())> auto operator()(copy_tag, It1, It2) const -> std::pair<iterator_value_t<It1>, iterator_value_t<It2>>; // pair reference template<typename It1, typename It2, CONCEPT_REQUIRES_(Readable<It1>() && Readable<It2>())> auto operator()(It1 const &it1, It2 const &it2) const noexcept(noexcept(iterator_reference_t<It1>(*it1)) && noexcept(iterator_reference_t<It2>(*it2))) RANGES_DECLTYPE_AUTO_RETURN
bool iter_next(struct iter *iter) { assert(iter); assert(iter->buffer); return !*(iter->buffer) ? false : !iter->item ? (iter->item = iter->buffer) : *(iter_move(iter)); }
static I impl(I begin, I end, C pred, P proj, D len, Pair p, detail::bidirectional_iterator_tag_ bi) { // *begin is known to be false // *end is known to be true // len >= 2 if(len == 2) { ranges::iter_swap(begin, end); return end; } if(len == 3) { I tmp = begin; if(invoke(pred, invoke(proj, *++tmp))) { ranges::iter_swap(begin, tmp); ranges::iter_swap(tmp, end); return end; } ranges::iter_swap(tmp, end); ranges::iter_swap(begin, tmp); return tmp; } if(len <= p.second) { // The buffer is big enough to use // Move the falses into the temporary buffer, and the trues to the front // of the line Update begin to always point to the end of the trues auto tmpbuf = ranges::make_raw_buffer(p.first); auto buf = tmpbuf.begin(); *buf = iter_move(begin); ++buf; auto res = partition_copy(make_move_iterator(next(begin)), make_move_sentinel(end), begin, buf, std::ref(pred), std::ref(proj)); begin = res.out1; // move *end, known to be true *begin = iter_move(res.in); ++begin; // All trues now at start of range, all falses in buffer // Move falses back into range, but don't mess up begin which points to // first false ranges::move(p.first, res.out2.base().base(), begin); // h destructs moved-from values out of the temp buffer, but doesn't // deallocate buffer return begin; } // Else not enough buffer, do in place // len >= 4 I middle = begin; D half = len / 2; // half >= 2 advance(middle, half); // recurse on [begin, middle-1], except reduce middle-1 until *(middle-1) is // true, *begin know to be false F????????????????T f m l I m1 = middle; I begin_false = begin; D len_half = half; while(!invoke(pred, invoke(proj, *--m1))) { if(m1 == begin) goto first_half_done; --len_half; } // F???TFFF?????????T // f m1 m l begin_false = stable_partition_fn::impl(begin, m1, pred, proj, len_half, p, bi); first_half_done: // TTTFFFFF?????????T // f ff m l // recurse on [middle, end], except increase middle until *(middle) is false, // *end know to be true m1 = middle; len_half = len - half; while(invoke(pred, invoke(proj, *m1))) { if(++m1 == end) return ranges::rotate(begin_false, middle, ++end).begin(); --len_half; } // TTTFFFFFTTTF?????T // f ff m m1 l I end_false = stable_partition_fn::impl(m1, end, pred, proj, len_half, p, bi); // TTTFFFFFTTTTTFFFFF // f ff m sf l return ranges::rotate(begin_false, middle, end_false).begin(); // TTTTTTTTFFFFFFFFFF // | }
inline void unguarded_insertion_sort(I begin, I end, C &pred, P &proj) { for(I i = begin; i != end; ++i) detail::unguarded_linear_insert(i, iter_move(i), pred, proj); }