#ifndef CORE_ALGORITHM_HPP #define CORE_ALGORITHM_HPP #include #include #include #include namespace core { inline namespace v2 { namespace impl { template bool equal ( range r1, range r2, Predicate&& p, ::std::random_access_iterator_tag, ::std::random_access_iterator_tag ) { if (r1.size() != r2.size()) { return false; } return ::std::equal( begin(r1), end(r1), begin(r2), ::core::forward(p) ); } template bool equal ( range r1, range r2, Predicate&& p, ::std::input_iterator_tag, ::std::input_iterator_tag ) { while (not r1.empty() and not r2.empty()) { if ( not ::core::invoke( ::core::forward(p), r1.front(), r2.front()) ) { return false; } r1.pop_front(); r2.pop_front(); } return r1.empty() and r2.empty(); } } /* namespace impl */ /* non-range based algorithms */ template constexpr T const& min (T const& lhs, T const& rhs) { return (rhs < lhs) ? rhs : lhs; } template constexpr T const& min (T const& lhs, T const& rhs, Compare compare) { return compare(rhs, lhs) ? rhs : lhs; } template constexpr T const& max (T const& lhs, T const& rhs) { return (lhs < rhs) ? rhs : lhs; } template constexpr T const& max (T const& lhs, T const& rhs, Compare compare) { return compare(lhs, rhs) ? rhs : lhs; } /* extensions */ template > constexpr T const& clamp ( T const& value, T const& low, T const& high, Compare compare = Compare { } ) { return compare(value, low) ? low : compare(high, value) ? high : value; } /* N4318 (modified) */ template < class T, class Compare = ::core::less<>, class Difference = ::core::minus<> > constexpr auto abs_diff ( T const& a, T const& b, Compare compare = Compare { }, Difference diff = Difference { } ) -> decltype(compare(a, b) ? diff(b, a) : diff(a, b)) { return compare(a, b) ? diff(b, a) : diff(a, b); } /* non-modifying sequence algorithms */ template auto all_of (Range&& rng, UnaryPredicate&& p) -> meta::when< is_range::value, bool > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "all_of requires InputIterators"); return ::std::all_of( ::std::begin(range), ::std::end(range), ::core::forward(p) ); } template auto any_of (Range&& rng, UnaryPredicate&& p) -> enable_if_t< is_range::value, bool > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "any_of requires InputIterators"); return ::std::any_of( ::std::begin(range), ::std::end(range), ::core::forward(p) ); } template auto none_of (Range&& rng, UnaryPredicate&& p) -> enable_if_t< is_range::value, bool > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "none_of requires InputIterators"); return ::std::none_of( ::std::begin(range), ::std::end(range), ::core::forward(p) ); } template auto for_each (Range&& rng, UnaryFunction&& f) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "for_each requires InputIterators"); return ::std::for_each( ::std::begin(range), ::std::end(range), ::core::forward(f) ); } template UnaryFunction for_each_if (Range&& r, UnaryFunction uf, UnaryPredicate up) { auto range = make_range(::core::forward(r)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "for_each_if requires InputIterators"); while (not range.empty()) { if (up(range.front())) { uf(range.front()); } range.pop_front(); } return uf; } template auto for_each_while ( Range&& r, UnaryFunction f, UnaryPredicate p ) -> decltype(begin(make_range(::core::forward(r)))) { auto range = make_range(::core::forward(r)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "for_each_while requires InputIterators"); while (not range.empty()) { if (not p(range.front())) { break; } f(range.front()); range.pop_front(); } return range.begin(); } template auto for_each_until ( Range&& r, UnaryFunction f, T const& value ) -> decltype(begin(make_range(::core::forward(r)))) { auto range = make_range(::core::forward(r)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "for_each_until requires InputIterators"); while (not range.empty()) { if (range.front() == value) { break; } f(range.front()); range.pop_front(); } return range.begin(); } template auto count (Range&& rng, T const& value) -> enable_if_t< is_range::value, decltype( ::std::count( ::std::begin(::core::forward(rng)), ::std::end(::core::forward(rng)), value ) ) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "count requires InputIterators"); return ::std::count(::std::begin(range), ::std::end(range), value); } template auto count_if (Range&& rng, UnaryPredicate&& p) -> enable_if_t< is_range::value, decltype( ::std::count_if( ::std::begin(::core::forward(rng)), ::std::end(::core::forward(rng)), ::core::forward(p) ) ) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "count_if requires InputIterators"); return ::std::count_if( ::std::begin(range), ::std::end(range), ::core::forward(p) ); } template ::std::pair mismatch ( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate predicate ) { auto r1 = make_range(first1, last1); auto r2 = make_range(first2, last2); while (not r1.empty() and not r2.empty()) { if (not predicate(r1.front(), r2.front())) { break; } r1.pop_front(); r2.pop_front(); } return ::std::make_pair(r1.begin(), r2.begin()); } template ::std::pair mismatch ( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2 ) { return (mismatch)(first1, last1, first2, last2, equal_to<> { }); } template < class Range1, class Range2, class BinaryPred, meta::require< meta::all_of, is_range>() > = __LINE__ > auto mismatch (Range1&& r1, Range2&& r2, BinaryPred&& bp) -> ::std::pair< decltype(::std::begin(::core::forward(r1))), decltype(::std::begin(::core::forward(r2))) > { auto range1 = make_range(::core::forward(r1)); auto range2 = make_range(::core::forward(r2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1 and is_input2, "mismatch requires InputIterators"); return (mismatch)( range1.begin(), range1.end(), range2.begin(), range2.end(), ::core::forward(bp)); } template < class Range, class InputIt, meta::require< meta::all::value, meta::none::value>()>() > = __LINE__ > auto mismatch(Range&& rng, InputIt&& it) -> ::std::pair< decltype(make_range(::core::forward(rng)).begin()), decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "mismatch requires InputIterators"); return ::std::mismatch( ::std::begin(range), ::std::end(range), ::core::forward(it) ); } template < class Range, class InputIt, class BinaryPredicate, meta::require< meta::all::value, meta::none>()>() > = __LINE__ > auto mismatch(Range&& r, InputIt&& it, BinaryPredicate&& bp) -> ::std::pair< decltype(core::make_range(::core::forward(r).begin())), decay_t > { auto range = make_range(::core::forward(r)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "mismatch requires InputIterators"); return ::std::mismatch( ::std::begin(range), ::std::end(range), ::core::forward(it), ::core::forward(bp) ); } template bool equal ( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate bp ) { auto r1 = make_range(first1, last1); auto r2 = make_range(first2, last2); using tag1 = typename decltype(r1)::iterator_category; using tag2 = typename decltype(r2)::iterator_category; return impl::equal(r1, r2, bp, tag1 { }, tag2 { }); } template bool equal (InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) { return equal(first1, last1, first2, last2, equal_to<> { }); } template < class Range1, class Range2, meta::require< meta::all_of, is_range>() > = __LINE__ > bool equal (Range1&& range1, Range2&& range2) { auto r1 = make_range(::core::forward(range1)); auto r2 = make_range(::core::forward(range2)); static constexpr auto is_input1 = decltype(r1)::is_input; static constexpr auto is_input2 = decltype(r2)::is_input; static_assert(is_input1, "equal requires InputIterators"); static_assert(is_input2, "equal requires InputIterators"); return (equal)(r1.begin(), r1.end(), r2.begin(), r2.end()); } template < class Range1, class Range2, class BinaryPredicate, meta::require< meta::all_of, is_range>() > = __LINE__ > bool equal (Range1&& range1, Range2&& range2, BinaryPredicate&& bp) { auto r1 = make_range(::core::forward(range1)); auto r2 = make_range(::core::forward(range2)); static constexpr auto is_input1 = decltype(r1)::is_input; static constexpr auto is_input2 = decltype(r2)::is_input; static_assert(is_input1, "equal requires InputIterators"); static_assert(is_input2, "equal requires InputIterators"); return equal( r1.begin(), r1.end(), r2.begin(), r2.end(), ::core::forward(bp) ); } template < class Range, class InputIt, meta::require< meta::all::value, meta::none::value>()>() > = __LINE__ > bool equal (Range&& rng, InputIt&& it) { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "equal requires InputIterators"); return ::std::equal( ::std::begin(range), ::std::end(range), ::core::forward(it) ); } template < class Range, class InputIt, class BinaryPredicate, meta::require< meta::all::value, meta::none>()>() > = __LINE__ > bool equal (Range&& rng, InputIt&& it, BinaryPredicate&& bp) { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "equal requires InputIterators"); return ::std::equal( ::std::begin(range), ::std::end(range), ::core::forward(it), ::core::forward(bp) ); } template auto find (Range&& rng, T const& value) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "find requires InputIterators"); return ::std::find(::std::begin(range), ::std::end(range), value); } template auto find_if (Range&& rng, UnaryPredicate&& p) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "find_if requires InputIterators"); return ::std::find_if( ::std::begin(range), ::std::end(range), ::core::forward(p) ); } template auto find_if_not (Range&& rng, UnaryPredicate&& p) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "find_if_not requires InputIterators"); return ::std::find_if_not( ::std::begin(range), ::std::end(range), ::core::forward(p) ); } template auto find_end (Range1&& rng1, Range2&& rng2) -> meta::when< meta::all_of, is_range>(), decltype(::std::begin(::core::forward(rng1))) > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_forward1 = decltype(range1)::is_forward; static constexpr auto is_forward2 = decltype(range2)::is_forward; static_assert(is_forward1, "find_end requires ForwardIterators"); static_assert(is_forward2, "find_end requires ForwardIterators"); return ::std::find_end( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2) ); } template auto find_end (Range1&& rng1, Range2&& rng2, BinaryPred& bp) -> meta::when< meta::all_of, is_range>(), decltype(::std::begin(::core::forward(rng1))) > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_forward1 = decltype(range1)::is_forward; static constexpr auto is_forward2 = decltype(range2)::is_forward; static_assert(is_forward1, "find_end requires ForwardIterators"); static_assert(is_forward2, "find_end requires ForwardIterators"); return ::std::find_end( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(bp) ); } template auto find_first_of (IRange&& irng, FRange&& frng) -> meta::when< meta::all_of, is_range>(), decltype(::std::begin(::core::forward(irng))) > { auto irange = make_range(::core::forward(irng)); auto frange = make_range(::core::forward(frng)); static constexpr auto is_input = decltype(irange)::is_input; static constexpr auto is_forward = decltype(frange)::is_forward; static_assert(is_input, "find_first_of requires InputIterators"); static_assert(is_forward, "find_first_of requires ForwardIterators"); return ::std::find_first_of( ::std::begin(irange), ::std::end(irange), ::std::begin(frange), ::std::end(frange) ); } template auto find_first_of ( IRange&& irng, FRange&& frng, BinaryPred&& bp ) -> meta::when< meta::all_of, is_range>(), decltype(::std::begin(::core::forward(irng))) > { auto irange = make_range(::core::forward(irng)); auto frange = make_range(::core::forward(frng)); static constexpr auto is_input = decltype(irange)::is_input; static constexpr auto is_forward = decltype(frange)::is_forward; static_assert(is_input, "find_first_of requires InputIterators"); static_assert(is_forward, "find_first_of requires ForwardIterators"); return ::std::find_first_of( ::std::begin(irange), ::std::end(irange), ::std::begin(frange), ::std::end(frange), ::core::forward(bp) ); } template auto adjacent_find (Range&& rng) -> meta::when< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "adjacent_find requires ForwardIterators"); return ::std::adjacent_find(::std::begin(range), ::std::end(range)); } template auto adjacent_find (Range&& rng, BinaryPredicate&& bp) -> meta::when< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "adjacent_find requires ForwardIterators"); return ::std::adjacent_find( ::std::begin(range), ::std::end(range), ::core::forward(bp) ); } template auto search (Range1&& rng1, Range2&& rng2) -> meta::when< meta::all_of, is_range>(), decltype(::std::begin(::core::forward(rng1))) > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_forward1 = decltype(range1)::is_forward; static constexpr auto is_forward2 = decltype(range2)::is_forward; static_assert(is_forward1, "search requires ForwardIterators"); static_assert(is_forward2, "search requires ForwardIterators"); return ::std::search( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2) ); } template auto search (Range1&& rng1, Range2&& rng2, BinaryPred&& bp) -> enable_if_t< meta::all_of, is_range>(), decltype(::std::begin(::core::forward(rng1))) > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_forward1 = decltype(range1)::is_forward; static constexpr auto is_forward2 = decltype(range2)::is_forward; static_assert(is_forward1, "search requires ForwardIterators"); static_assert(is_forward2, "search requires ForwardIterators"); return ::std::search( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(bp) ); } template auto search_n (Range&& rng, Size&& count, T const& value) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "search_n requires ForwardIterators"); return ::std::search_n( ::std::begin(range), ::std::end(range), ::core::forward(count), value ); } template auto search_n ( Range&& rng, Size&& count, T const& value, BinaryPred&& bp ) -> meta::when< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "search_n requires ForwardIterators"); return ::std::search_n( ::std::begin(range), ::std::end(range), ::core::forward(count), value, ::core::forward(bp) ); } /* modifying sequence algorithms */ template auto copy (Range&& rng, OutputIt&& it) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "copy requires InputIterators"); return ::std::copy( ::std::begin(range), ::std::end(range), ::core::forward(it) ); } template auto copy_if (Range&& rng, OutputIt&& it, UnaryPredicate&& up) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "copy_if requires InputIterators"); return ::std::copy_if( ::std::begin(range), ::std::end(range), ::core::forward(it), ::core::forward(up) ); } template OutputIt copy_until (Range&& r, OutputIt it, T const& value) { auto range = make_range(::core::forward(r)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "copy_until requires InputIterators"); while (not range.empty()) { if (range.front() == value) { break; } *it++ = range.front(); range.pop_front(); } return it; } template auto copy_backward (Range&& rng, BidirIt&& it) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_bidir = decltype(range)::is_bidirectional; static_assert(is_bidir, "copy_backward requires BidirectionalIterators"); return ::std::copy_backward( ::std::begin(range), ::std::end(range), ::core::forward(it) ); } template auto move (Range&& rng, OutputIt&& it) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "move requires InputIterators"); return ::std::move( ::std::begin(range), ::std::end(range), ::core::forward(it) ); } template auto move_backward (Range&& rng, BidirIt&& it) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_bidir = decltype(range)::is_bidirectional; static_assert(is_bidir, "move_backward requires BidirectionalIterators"); return ::std::move_backward( ::std::begin(range), ::std::end(range), ::core::forward(it) ); } template auto fill (Range&& rng, T const& value) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "fill requires ForwardIterators"); return ::std::fill(::std::begin(range), ::std::end(range), value); } template auto transform ( Range&& rng, OutputIt&& it, UnaryOperation&& op ) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "transform requires InputIterators"); return ::std::transform( ::std::begin(range), ::std::end(range), ::core::forward(it), ::core::forward(op) ); } template auto transform_if ( Range&& rng, OutputIt it, UnaryOperation op, UnaryPred up ) -> enable_if_t< is_range::value, OutputIt > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "transform_if requires ForwardIterators"); while (not range.empty()) { if (invoke(up, range.front())) { *it = invoke(op, range.front()); ++it; } range.pop_front(); } return it; } template OutputIt transform_n (InputIt in, Size count, OutputIt out, UnaryOp op) { while (count > 0) { *out = invoke(op, *in); ++out; ++in; --count; } return out; } template < class InputIt1, class InputIt2, class Size, class OutputIt, class UnaryOp > OutputIt transform_n ( InputIt1 in1, InputIt2 in2, Size count, OutputIt out, UnaryOp op ) { while (count > 0) { *out = invoke(op, *in1, *in2); ++out; ++in1; ++in2; --count; } return out; } template < class Range, class InputIt, class OutputIt, class BinaryOperation, meta::require< meta::all::value, meta::none::value>()>() > = __LINE__ > decay_t transform ( Range&& r, InputIt&& in, OutputIt&& out, BinaryOperation&& op ) { auto range = make_range(::core::forward(r)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "transform requires InputIterators"); return ::std::transform( range.begin(), range.end(), ::core::forward(in), ::core::forward(out), ::core::forward(op)); } template < class Range1, class Range2, class OutputIt, class BinaryOperation, meta::require< meta::all_of, is_range>() > = __LINE__ > decay_t transform ( Range1&& rng1, Range2&& rng2, OutputIt&& it, BinaryOperation&& op ) { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "transform requires InputIterators"); static_assert(is_input2, "transform requires InputIterators"); return ::std::transform( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::core::forward(it), ::core::forward(op) ); } template < class Range1, class Range2, class OutputIt, class BinaryOperation, class BinaryPredicate > auto transform_if ( Range1&& rng1, Range2&& rng2, OutputIt it, BinaryOperation op, BinaryPredicate bp ) -> meta::when< meta::all_of, is_range>(), OutputIt > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_forward1 = decltype(range1)::is_forward; static constexpr auto is_forward2 = decltype(range2)::is_forward; static_assert(is_forward1, "transform_if requires ForwardIterators"); static_assert(is_forward2, "transform_if requires ForwardIterators"); while (not range1.empty()) { if (bp(range1.front(), range2.front())) { *it = op(range1.front(), range2.front()); ++it; } range1.pop_front(); range2.pop_front(); } return it; } template auto remove (Range&& rng, T const& value) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "remove requires ForwardIterators"); return ::std::remove(::std::begin(range), ::std::end(range), value); } template auto remove_if (Range&& rng, UnaryPredicate&& up) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "remove_if requires ForwardIterators"); return ::std::remove_if( ::std::begin(range), ::std::end(range), ::core::forward(up) ); } template auto remove_copy (Range&& rng, OutputIt&& it, T const& value) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "remove_copy requires InputIterators"); return ::std::remove_copy( ::std::begin(range), ::std::end(range), ::core::forward(it), value ); } template auto remove_copy_if (Range&& rng, OutputIt&& it, UnaryPred&& up) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "remove_copy_if requires InputIterators"); return ::std::remove_copy_if( ::std::begin(range), ::std::end(range), ::core::forward(it), ::core::forward(up) ); } template auto remove_erase (Range&& rng, T const& val) -> enable_if_t< is_range::value > { ::core::forward(rng).erase( remove(::core::forward(rng), val), ::std::end(::core::forward(rng)) ); } template auto remove_erase_if (Range&& rng, UnaryPred&& up) -> enable_if_t< is_range::value > { ::core::forward(rng).erase( remove_if( ::core::forward(rng), ::core::forward(up) ), ::std::end(::core::forward(rng)) ); } template auto replace (Range&& rng, T const& old, T const& value) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_input; static_assert(is_forward, "replace requires ForwardIterators"); return ::std::replace( ::std::begin(range), ::std::end(range), old, value ); } template auto replace_if (Range&& rng, UnaryPred&& up, T const& value) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "replace_if requires ForwardIterators"); return ::std::replace_if( ::std::begin(range), ::std::end(range), ::core::forward(up), value ); } template auto replace_copy ( Range&& rng, OutputIt&& it, T const& old, T const& value ) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "replace_copy requires InputIterators"); return ::std::replace_copy( ::std::begin(range), ::std::end(range), ::core::forward(it), old, value ); } template auto replace_copy_if ( Range&& rng, OutputIt&& it, UnaryPred&& up, T const& value ) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "replace_copy_if requires InputIterators"); return ::std::replace_copy_if( ::std::begin(range), ::std::end(range), ::core::forward(it), ::core::forward(up), value ); } template auto swap_ranges (Range&& rng, ForwardIt&& it) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "swap_ranges requires ForwardIterators"); return ::std::swap_ranges( ::std::begin(range), ::std::end(range), ::core::forward(it) ); } template auto reverse (Range&& rng) -> enable_if_t::value> { auto range = make_range(::core::forward(rng)); static constexpr auto is_bidir = decltype(range)::is_bidirectional; static_assert(is_bidir, "reverse requires BidirectionalIterators"); return ::std::reverse(::std::begin(range), ::std::end(range)); } template auto reverse_copy (Range&& rng, OutputIt&& it) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_bidir = decltype(range)::is_bidirectional; static_assert(is_bidir, "reverse_copy requires BidirectionalIterators"); return ::std::reverse_copy( ::std::begin(range), ::std::end(range), ::core::forward(it) ); } template auto rotate (Range&& rng, ForwardIt&& it) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "rotate requires ForwardIterators"); ::std::rotate( ::std::begin(range), ::core::forward(it), ::std::end(range) ); } template auto rotate_copy (Range&& rng, ForwardIt&& it, OutputIt&& ot) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "rotate_copy requires ForwardIterators"); return ::std::rotate_copy( ::std::begin(range), ::core::forward(it), ::std::end(range), ::core::forward(ot) ); } template auto shuffle (Range&& rng, URNG&& g) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "shuffle requires RandomAccessIterators"); return ::std::shuffle( ::std::begin(range), ::std::end(range), ::core::forward(g) ); } template auto unique (Range&& rng) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "unique requires ForwardIterators"); return ::std::unique(::std::begin(range), ::std::end(range)); } template auto unique (Range&& rng, BinaryPredicate&& bp) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "unique requires ForwardIterators"); return ::std::unique( ::std::begin(range), ::std::end(range), ::core::forward(bp) ); } template auto unique_copy (Range&& rng, OutputIt&& it) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "unique_copy requires InputIterators"); return ::std::unique_copy( ::std::begin(range), ::std::end(range), ::core::forward(it) ); } template auto unique_copy (Range&& rng, OutputIt&& it, BinaryPred&& bp) -> enable_if_t< is_range::value, decay_t > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "unique_copy requires InputIterators"); return ::std::unique_copy( ::std::begin(range), ::std::end(range), ::core::forward(it), ::core::forward(bp) ); } /* partitioning operations */ template auto is_partitioned (Range&& rng, UnaryPredicate&& up) -> enable_if_t< is_range::value, bool > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "is_partitioned requires InputIterators"); return ::std::is_partitioned( ::std::begin(range), ::std::end(range), ::core::forward(up) ); } template auto partition (Range&& rng, UnaryPredicate&& up) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "partition requires ForwardIterators"); return ::std::partition( ::std::begin(range), ::std::end(range), ::core::forward(up) ); } template auto partition_copy ( Range&& rng, OutputTrue&& ot, OutputFalse&& of, UnaryPred&& up ) -> enable_if_t< is_range::value, ::std::pair, decay_t> > { auto range = make_range(::core::forward(rng)); static constexpr auto is_input = decltype(range)::is_input; static_assert(is_input, "partition_copy requires InputIterators"); return ::std::partition_copy( ::std::begin(range), ::std::end(range), ::core::forward(ot), ::core::forward(of), ::core::forward(up) ); } template auto stable_partition (Range&& rng, UnaryPredicate&& up) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_bidir = decltype(range)::is_bidirectional; static_assert(is_bidir, "stable_partition requires BidirectionalIterators"); return ::std::stable_partition( ::std::begin(range), ::std::end(range), ::core::forward(up) ); } template auto partition_point (Range&& rng, UnaryPredicate&& up) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "partition_point requires ForwardIterators"); return ::std::partition_point( ::std::begin(range), ::std::end(range), ::core::forward(up) ); } /* sorting operations */ template auto is_sorted (Range&& rng) -> enable_if_t::value, bool> { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "is_sorted requires ForwardIterators"); return ::std::is_sorted(::std::begin(range), ::std::end(range)); } template auto is_sorted (Range&& rng, Compare&& compare) -> enable_if_t< is_range::value, bool > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "is_sorted requires ForwardIterators"); return ::std::is_sorted( ::std::begin(range), ::std::end(range), ::core::forward(compare) ); } template auto is_sorted_until (Range&& rng) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "is_sorted_until requires ForwardIterators"); return ::std::is_sorted_until(::std::begin(range), ::std::end(range)); } template auto is_sorted_until (Range&& rng, Compare&& compare) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "is_sorted_until requires ForwardIterators"); return ::std::is_sorted_until( ::std::begin(range), ::std::end(range), ::core::forward(compare) ); } template auto sort (Range&& rng) -> enable_if_t::value> { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "sort requires RandomAccessIterators"); return ::std::sort(::std::begin(range), ::std::end(range)); } template auto sort (Range&& rng, Compare&& cmp) -> enable_if_t::value> { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "sort requires RandomAccessIterators"); return ::std::sort( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } template auto partial_sort (Range&& rng, RandomIt&& it) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "partial_sort requires RandomAccessIterators"); return ::std::partial_sort( ::std::begin(range), ::core::forward(it), ::std::end(range) ); } template auto partial_sort (Range&& rng, RandomIt&& it, Compare&& cmp) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "partial_sort requires RandomAccessIterators"); return ::std::partial_sort( ::std::begin(range), ::core::forward(it), ::std::end(range), ::core::forward(cmp) ); } template auto partial_sort_copy (IRange&& irng, RRange&& rrng) -> meta::when< meta::all_of, is_range>(), decltype(::std::begin(::core::forward(rrng))) > { auto irange = make_range(::core::forward(irng)); auto rrange = make_range(::core::forward(rrng)); static constexpr auto is_input = decltype(irange)::is_input; static constexpr auto is_random = decltype(rrange)::is_random_access; static_assert(is_input, "partial_sort_copy requires InputIterators"); static_assert(is_random, "partial_sort_copy requires RandomAccessIterators"); return ::std::partial_sort_copy( ::std::begin(irange), ::std::end(irange), ::std::begin(rrange), ::std::end(rrange) ); } template auto partial_sort_copy ( IRange&& irng, RRange&& rrng, Compare&& cmp ) -> meta::when< meta::all_of, is_range>(), decltype(::std::begin(::core::forward(rrng))) > { auto irange = make_range(::core::forward(irng)); auto rrange = make_range(::core::forward(rrng)); static constexpr auto is_input = decltype(irange)::is_input; static constexpr auto is_random = decltype(rrange)::is_random_access; static_assert(is_input, "partial_sort_copy requires InputIterators"); static_assert(is_random, "partial_sort_copy requires RandomAccessIterators"); return ::std::partial_sort_copy( ::std::begin(irange), ::std::end(irange), ::std::begin(rrange), ::std::end(rrange), ::core::forward(cmp) ); } template auto stable_sort (Range&& rng) -> enable_if_t::value> { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "stable_sort requires RandomAccessIterators"); return ::std::stable_sort(::std::begin(range), ::std::end(range)); } template auto stable_sort (Range&& rng, Compare&& cmp) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "stable_sort requires RandomAccessIterators"); return ::std::stable_sort( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } template auto nth_element (Range&& rng, RandomIt&& it) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "nth_element requires RandomAccessIterators"); return ::std::nth_element( ::std::begin(range), ::core::forward(it), ::std::end(range) ); } template auto nth_element (Range&& rng, RandomIt&& it, Compare&& cmp) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "nth_element requires RandomAccessIterators"); return ::std::nth_element( ::std::begin(range), ::core::forward(it), ::std::end(range), ::core::forward(cmp) ); } /* binary search operations (on sorted ranges) */ template auto lower_bound (Range&& rng, T const& value) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "lower_bound requires ForwardIterators"); return ::std::lower_bound(::std::begin(range), ::std::end(range), value); } template auto lower_bound (Range&& rng, T const& value, Compare&& cmp) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "lower_bound requires ForwardIterators"); return ::std::lower_bound( ::std::begin(range), ::std::end(range), value, ::core::forward(cmp) ); } template auto upper_bound (Range&& rng, T const& value) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "upper_bound requires ForwardIterators"); return ::std::upper_bound(::std::begin(range), ::std::end(range), value); } template auto upper_bound (Range&& rng, T const& value, Compare&& cmp) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "upper_bound requires ForwardIterators"); return ::std::upper_bound( ::std::begin(range), ::std::end(range), value, ::core::forward(cmp) ); } template auto binary_search (Range&& rng, T const& value) -> enable_if_t< is_range::value, bool > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "binary_search requires ForwardIterators"); return ::std::binary_search(::std::begin(range), ::std::end(range), value); } template auto binary_search (Range&& rng, T const& value, Compare&& cmp) -> enable_if_t< is_range::value, bool > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "binary_search requires ForwardIterators"); return ::std::binary_search( ::std::begin(range), ::std::end(range), value, ::core::forward(cmp) ); } template auto equal_range (Range&& rng, T const& value) -> enable_if_t< is_range::value, range(rng)))> > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "equal_range requires ForwardIterators"); return ::std::equal_range(::std::begin(range), ::std::end(range), value); } template auto equal_range (Range&& rng, T const& value, Compare&& cmp) -> enable_if_t< is_range::value, range(rng)))> > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "equal_range requires ForwardIterators"); return ::std::equal_range( ::std::begin(range), ::std::end(range), value, ::core::forward(cmp) ); } /* set operations (on sorted ranges) */ template auto merge (Range1&& rng1, Range2&& rng2, OutputIt&& it) -> meta::when< meta::all_of, is_range>(), decay_t > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "merge requires InputIterators"); static_assert(is_input2, "merge requires InputIterators"); return ::std::merge( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(it) ); } template auto merge ( Range1&& rng1, Range2&& rng2, OutputIt&& it, Compare&& cmp ) -> enable_if_t< meta::all_of, is_range>(), decay_t > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "merge requires InputIterators"); static_assert(is_input2, "merge requires InputIterators"); return ::std::merge( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(it), ::core::forward(cmp) ); } template auto inplace_merge (Range&& rng, BidirIt&& it) -> meta::when< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_bidir = decltype(range)::is_bidirectional; static_assert(is_bidir, "inplace_merge requires BidirectionalIterators"); return ::std::inplace_merge( ::std::begin(range), ::core::forward(it), ::std::end(range) ); } template auto inplace_merge (Range&& rng, BidirIt&& it, Compare&& cmp) -> meta::when< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_bidir = decltype(range)::is_bidirectional; static_assert(is_bidir, "inplace_merge requires BidirectionalIterators"); return ::std::inplace_merge( ::std::begin(range), ::core::forward(it), ::std::end(range), ::core::forward(cmp) ); } template auto includes (Range1&& rng1, Range2&& rng2) -> meta::when< meta::all_of, is_range>(), bool > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "includes requires InputIterators"); static_assert(is_input2, "includes requires InputIterators"); return ::std::includes( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2) ); } template auto includes (Range1&& rng1, Range2&& rng2, Compare&& cmp) -> meta::when< meta::all_of, is_range>(), bool > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "includes requires InputIterators"); static_assert(is_input2, "includes requires InputIterators"); return ::std::includes( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(cmp) ); } template auto set_difference (Range1&& rng1, Range2&& rng2, OutputIt&& it) -> meta::when< meta::all_of, is_range>(), decay_t > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "set_difference requires InputIterators"); static_assert(is_input2, "set_difference requires InputIterators"); return ::std::set_difference( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(it) ); } template auto set_difference ( Range1&& rng1, Range2&& rng2, OutputIt&& it, Compare&& cmp ) -> meta::when< meta::all_of, is_range>(), decay_t > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "set_difference requires InputIterators"); static_assert(is_input2, "set_difference requires InputIterators"); return ::std::set_difference( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(it), ::core::forward(cmp) ); } template auto set_intersection (Range1&& rng1, Range2&& rng2, OutputIt&& it) -> meta::when< meta::all_of, is_range>(), decay_t > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "set_intersection requires InputIterators"); static_assert(is_input2, "set_intersection requires InputIterators"); return ::std::set_intersection( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(it) ); } template auto set_intersection ( Range1&& rng1, Range2&& rng2, OutputIt&& it, Compare&& cmp ) -> enable_if_t< meta::all_of, is_range>(), decay_t > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "set_intersection requires InputIterators"); static_assert(is_input2, "set_intersection requires InputIterators"); return ::std::set_intersection( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(it), ::core::forward(cmp) ); } template auto set_symmetric_difference (Range1&& rng1, Range2&& rng2, OutputIt&& it) -> enable_if_t< meta::all_of, is_range>(), decay_t > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "set_symmetric_difference requires InputIterators"); static_assert(is_input2, "set_symmetric_difference requires InputIterators"); return ::std::set_symmetric_difference( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(it) ); } template auto set_symmetric_difference ( Range1&& rng1, Range2&& rng2, OutputIt&& it, Compare&& cmp ) -> enable_if_t< meta::all_of, is_range>(), decay_t > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "set_symmetric_difference requires InputIterators"); static_assert(is_input2, "set_symmetric_difference requires InputIterators"); return ::std::set_symmetric_difference( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(it), ::core::forward(cmp) ); } template auto set_union (Range1&& rng1, Range2&& rng2, OutputIt&& it) -> enable_if_t< meta::all_of, is_range>(), decay_t > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "set_union requires InputIterators"); static_assert(is_input2, "set_union requires InputIterators"); return ::std::set_union( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(it) ); } template auto set_union ( Range1&& rng1, Range2&& rng2, OutputIt&& it, Compare&& cmp ) -> enable_if_t< meta::all_of, is_range>(), decay_t > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "set_union requires InputIterators"); static_assert(is_input2, "set_union requires InputIterators"); return ::std::set_union( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(it), ::core::forward(cmp) ); } /* heap operations */ template auto is_heap (Range&& rng) -> enable_if_t::value, bool> { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "is_heap requires RandomAccessIterators"); return ::std::is_heap(::std::begin(range), ::std::end(range)); } template auto is_heap (Range&& rng, Compare&& cmp) -> enable_if_t< is_range::value, bool > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "is_heap requires RandomAccessIterators"); return ::std::is_heap( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } template auto is_heap_until (Range&& rng) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "is_heap_until requires RandomAccessIterators"); return ::std::is_heap_until(::std::begin(range), ::std::end(range)); } template auto is_heap_until (Range&& rng, Compare&& cmp) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "is_heap_until requires RandomAccessIterators"); return ::std::is_heap_until( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } template auto make_heap (Range&& rng) -> enable_if_t::value> { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "make_heap requires RandomAccessIterators"); return ::std::make_heap(::std::begin(range), ::std::end(range)); } template auto make_heap (Range&& rng, Compare&& cmp) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "make_heap requires RandomAccessIterators"); return ::std::make_heap( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } template auto push_heap (Range&& rng) -> enable_if_t::value> { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "push_heap requires RandomAccessIterators"); return ::std::push_heap(::std::begin(range), ::std::end(range)); } template auto push_heap (Range&& rng, Compare&& cmp) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "push_heap requires RandomAccessIterators"); return ::std::push_heap( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } template auto pop_heap (Range&& rng) -> enable_if_t::value> { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "pop_heap requires RandomAccessIterators"); return ::std::pop_heap(::std::begin(range), ::std::end(range)); } template auto pop_heap (Range&& rng, Compare&& cmp) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "pop_heap requires RandomAccessIterators"); return ::std::pop_heap( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } template auto sort_heap (Range&& rng) -> enable_if_t::value> { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "sort_heap requires RandomAccessIterators"); return ::std::sort_heap(::std::begin(range), ::std::end(range)); } template auto sort_heap (Range&& rng, Compare&& cmp) -> enable_if_t< is_range::value > { auto range = make_range(::core::forward(rng)); static constexpr auto is_random = decltype(range)::is_random_access; static_assert(is_random, "sort_heap requires RandomAccessIterators"); return ::std::sort_heap( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } /* min/max operations */ template auto max_element (Range&& rng) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "max_element requires ForwardIterators"); return ::std::max_element(::std::begin(range), ::std::end(range)); } template auto max_element (Range&& rng, Compare&& cmp) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "max_element requires ForwardIterators"); return ::std::max_element( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } template auto min_element (Range&& rng) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "min_element requires ForwardIterators"); return ::std::min_element(::std::begin(range), ::std::end(range)); } template auto min_element (Range&& rng, Compare&& cmp) -> enable_if_t< is_range::value, decltype(::std::begin(::core::forward(rng))) > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "min_element requires ForwardIterators"); return ::std::min_element( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } template auto minmax_element (Range&& rng) -> enable_if_t< is_range::value, ::std::pair< decltype(::std::begin(::core::forward(rng))), decltype(::std::end(::core::forward(rng))) > > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "minmax_element requires ForwardIterators"); return ::std::minmax_element(::std::begin(range), ::std::end(range)); } template auto minmax_element (Range&& rng, Compare&& cmp) -> enable_if_t< is_range::value, ::std::pair< range(rng)))>, range(rng)))> > > { auto range = make_range(::core::forward(rng)); static constexpr auto is_forward = decltype(range)::is_forward; static_assert(is_forward, "minmax_element requires ForwardIterators"); return ::std::minmax_element( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } template auto lexicographical_compare (Range1&& rng1, Range2&& rng2) -> enable_if_t< meta::all_of, is_range>(), bool > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "lexicographical_compare requires InputIterators"); static_assert(is_input2, "lexicographical_compare requires InputIterators"); return ::std::lexicographical_compare( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2) ); } template auto lexicographical_compare ( Range1&& rng1, Range2&& rng2, Compare&& cmp ) -> enable_if_t< meta::all_of, is_range>(), bool > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_input1 = decltype(range1)::is_input; static constexpr auto is_input2 = decltype(range2)::is_input; static_assert(is_input1, "lexicographical_compare requires InputIterators"); static_assert(is_input2, "lexicographical_compare requires InputIterators"); return ::std::lexicographical_compare( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::std::end(range2), ::core::forward(cmp) ); } template auto is_permutation (Range1&& rng1, Range2&& rng2) -> enable_if_t< meta::all_of, is_range>(), bool > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_forward1 = decltype(range1)::is_forward; static constexpr auto is_forward2 = decltype(range2)::is_forward; static_assert(is_forward1, "is_permutation requires ForwardIterators"); static_assert(is_forward2, "is_permutation requires ForwardIterators"); return ::std::is_permutation( ::std::begin(range1), ::std::end(range1), ::std::begin(range2) ); } template auto is_permutation ( Range1&& rng1, Range2&& rng2, BinaryPredicate&& bp ) -> meta::when< meta::all_of, is_range>(), bool > { auto range1 = make_range(::core::forward(rng1)); auto range2 = make_range(::core::forward(rng2)); static constexpr auto is_forward1 = decltype(range1)::is_forward; static constexpr auto is_forward2 = decltype(range2)::is_forward; static_assert(is_forward1, "is_permutation requires ForwardIterators"); static_assert(is_forward2, "is_permutation requires ForwardIterators"); return ::std::is_permutation( ::std::begin(range1), ::std::end(range1), ::std::begin(range2), ::core::forward(bp) ); } template auto next_permutation (Range&& rng) -> enable_if_t< is_range::value, bool > { auto range = make_range(::core::forward(rng)); static constexpr auto is_bidir = decltype(range)::is_bidirectional; static_assert(is_bidir, "next_permutation requires BidirectionalIterators"); return ::std::next_permutation(::std::begin(range), ::std::end(range)); } template auto next_permutation (Range&& rng, Compare&& cmp) -> enable_if_t< is_range::value, bool > { auto range = make_range(::core::forward(rng)); static constexpr auto is_bidir = decltype(range)::is_bidirectional; static_assert(is_bidir, "next_permutation requires BidirectionalIterators"); return ::std::next_permutation( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } template auto prev_permutation (Range&& rng) -> enable_if_t< is_range::value, bool > { auto range = make_range(::core::forward(rng)); static constexpr auto is_bidir = decltype(range)::is_bidirectional; static_assert(is_bidir, "prev_permutation requires BidirectionalIterators"); return ::std::prev_permutation(::std::begin(range), ::std::end(range)); } template auto prev_permutation (Range&& rng, Compare&& cmp) -> enable_if_t< is_range::value, bool > { auto range = make_range(::core::forward(rng)); static constexpr auto is_bidir = decltype(range)::is_bidirectional; static_assert(is_bidir, "prev_permutation requires BidirectionalIterators"); return ::std::prev_permutation( ::std::begin(range), ::std::end(range), ::core::forward(cmp) ); } }} /* namespace core::v2 */ #endif /* CORE_ALGORITHM_HPP */