/* Algorithms for OctaSTD. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OSTD_ALGORITHM_HH #define OSTD_ALGORITHM_HH #include #include "ostd/functional.hh" #include "ostd/range.hh" #include "ostd/utility.hh" #include "ostd/initializer_list.hh" namespace ostd { /* partitioning */ template inline R partition(R range, U pred) { R ret = range; for (; !range.empty(); range.pop_front()) { if (pred(range.front())) { detail::swap_adl(range.front(), ret.front()); ret.pop_front(); } } return ret; } template inline auto partition(F &&func) { return [func = forward(func)](auto &&obj) mutable { return partition(forward(obj), forward(func)); }; } template inline bool is_partitioned(R range, P pred) { for (; !range.empty() && pred(range.front()); range.pop_front()); for (; !range.empty(); range.pop_front()) if (pred(range.front())) return false; return true; } template inline auto is_partitioned(F &&func) { return [func = forward(func)](auto &&obj) mutable { return is_partitioned(forward(obj), forward(func)); }; } /* sorting */ namespace detail { template static void insort(R range, C compare) { RangeSize rlen = range.size(); for (RangeSize i = 1; i < rlen; ++i) { RangeSize j = i; RangeValue v(move(range[i])); while (j > 0 && !compare(range[j - 1], v)) { range[j] = range[j - 1]; --j; } range[j] = move(v); } } template static void hs_sift_down(R range, RangeSize s, RangeSize e, C compare) { RangeSize r = s; while ((r * 2 + 1) <= e) { RangeSize ch = r * 2 + 1; RangeSize sw = r; if (compare(range[sw], range[ch])) sw = ch; if (((ch + 1) <= e) && compare(range[sw], range[ch + 1])) sw = ch + 1; if (sw != r) { detail::swap_adl(range[r], range[sw]); r = sw; } else return; } } template static void heapsort(R range, C compare) { RangeSize len = range.size(); RangeSize st = (len - 2) / 2; for (;;) { detail::hs_sift_down(range, st, len - 1, compare); if (st-- == 0) break; } RangeSize e = len - 1; while (e > 0) { detail::swap_adl(range[e], range[0]); --e; detail::hs_sift_down(range, 0, e, compare); } } template static void introloop(R range, C compare, RangeSize depth) { if (range.size() <= 10) { detail::insort(range, compare); return; } if (depth == 0) { detail::heapsort(range, compare); return; } detail::swap_adl(range[range.size() / 2], range.back()); RangeSize pi = 0; R pr = range; pr.pop_back(); for (; !pr.empty(); pr.pop_front()) { if (compare(pr.front(), range.back())) detail::swap_adl(pr.front(), range[pi++]); } detail::swap_adl(range[pi], range.back()); detail::introloop(range.slice(0, pi), compare, depth - 1); detail::introloop(range.slice(pi + 1, range.size()), compare, depth - 1); } template inline void introsort(R range, C compare) { detail::introloop(range, compare, RangeSize(2 * (log(range.size()) / log(2)))); } } /* namespace detail */ template inline R sort_cmp(R range, C compare) { detail::introsort(range, compare); return range; } template inline auto sort_cmp(C &&compare) { return [compare = forward(compare)](auto &&obj) mutable { return sort_cmp(forward(obj), forward(compare)); }; } template inline R sort(R range) { return sort_cmp(range, Less>()); } inline auto sort() { return [](auto &&obj) { return sort(forward(obj)); }; } /* min/max(_element) */ template inline const T &min(const T &a, const T &b) { return (a < b) ? a : b; } template inline const T &min_cmp(const T &a, const T &b, C compare) { return compare(a, b) ? a : b; } template inline const T &max(const T &a, const T &b) { return (a < b) ? b : a; } template inline const T &max_cmp(const T &a, const T &b, C compare) { return compare(a, b) ? b : a; } template inline R min_element(R range) { R r = range; for (; !range.empty(); range.pop_front()) if (ostd::min(r.front(), range.front()) == range.front()) r = range; return r; } template inline R min_element_cmp(R range, C compare) { R r = range; for (; !range.empty(); range.pop_front()) if (ostd::min_cmp(r.front(), range.front(), compare) == range.front()) r = range; return r; } inline auto min_element() { return [](auto &&obj) { return min_element(forward(obj)); }; } template inline auto min_element_cmp(C &&compare) { return [compare = forward(compare)](auto &&obj) mutable { return min_element_cmp(forward(obj), forward(compare)); }; } template inline R max_element(R range) { R r = range; for (; !range.empty(); range.pop_front()) if (ostd::max(r.front(), range.front()) == range.front()) r = range; return r; } template inline R max_element_cmp(R range, C compare) { R r = range; for (; !range.empty(); range.pop_front()) if (ostd::max_cmp(r.front(), range.front(), compare) == range.front()) r = range; return r; } inline auto max_element() { return [](auto &&obj) { return max_element(forward(obj)); }; } template inline auto max_element_cmp(C &&compare) { return [compare = forward(compare)](auto &&obj) mutable { return max_element_cmp(forward(obj), forward(compare)); }; } template inline T min(std::initializer_list il) { return ostd::min_element(ostd::iter(il)).front(); } template inline T min_cmp(std::initializer_list il, C compare) { return ostd::min_element_cmp(ostd::iter(il), compare).front(); } template inline T max(std::initializer_list il) { return ostd::max_element(ostd::iter(il)).front(); } template inline T max_cmp(std::initializer_list il, C compare) { return ostd::max_element_cmp(ostd::iter(il), compare).front(); } /* clamp */ template inline T clamp(const T &v, const U &lo, const U &hi) { return ostd::max(T(lo), ostd::min(v, T(hi))); } template inline T clamp(const T &v, const U &lo, const U &hi, C compare) { return ostd::max_cmp(T(lo), ostd::min_cmp(v, T(hi), compare), compare); } /* lexicographical compare */ template inline bool lexicographical_compare(R1 range1, R2 range2) { while (!range1.empty() && !range2.empty()) { if (range1.front() < range2.front()) return true; if (range2.front() < range1.front()) return false; range1.pop_front(); range2.pop_front(); } return (range1.empty() && !range2.empty()); } template inline auto lexicographical_compare(R &&range) { return [range = forward(range)](auto &&obj) mutable { return lexicographical_compare(forward(obj), forward(range)); }; } template inline bool lexicographical_compare_cmp(R1 range1, R2 range2, C compare) { while (!range1.empty() && !range2.empty()) { if (compare(range1.front(), range2.front())) return true; if (compare(range2.front(), range1.front())) return false; range1.pop_front(); range2.pop_front(); } return (range1.empty() && !range2.empty()); } template inline auto lexicographical_compare_cmp(R &&range, C &&compare) { return [range = forward(range), compare = forward(compare)](auto &&obj) mutable { return lexicographical_compare_cmp(forward(obj), forward(range), forward(compare)); }; } /* algos that don't change the range */ template inline F for_each(R range, F func) { for (; !range.empty(); range.pop_front()) func(range.front()); return move(func); } template inline auto for_each(F &&func) { return [func = forward(func)](auto &&obj) mutable { return for_each(forward(obj), forward(func)); }; } template inline bool all_of(R range, P pred) { for (; !range.empty(); range.pop_front()) if (!pred(range.front())) return false; return true; } template inline auto all_of(F &&func) { return [func = forward(func)](auto &&obj) mutable { return all_of(forward(obj), forward(func)); }; } template inline bool any_of(R range, P pred) { for (; !range.empty(); range.pop_front()) if (pred(range.front())) return true; return false; } template inline auto any_of(F &&func) { return [func = forward(func)](auto &&obj) mutable { return any_of(forward(obj), forward(func)); }; } template inline bool none_of(R range, P pred) { for (; !range.empty(); range.pop_front()) if (pred(range.front())) return false; return true; } template inline auto none_of(F &&func) { return [func = forward(func)](auto &&obj) mutable { return none_of(forward(obj), forward(func)); }; } template inline R find(R range, const T &v) { for (; !range.empty(); range.pop_front()) if (range.front() == v) break; return range; } template inline auto find(T &&v) { return [v = forward(v)](auto &&obj) mutable { return find(forward(obj), forward(v)); }; } template inline R find_last(R range, const T &v) { range = find(range, v); if (!range.empty()) for (;;) { R prev = range; prev.pop_front(); R r = find(prev, v); if (r.empty()) break; range = r; } return range; } template inline auto find_last(T &&v) { return [v = forward(v)](auto &&obj) mutable { return find_last(forward(obj), forward(v)); }; } template inline R find_if(R range, P pred) { for (; !range.empty(); range.pop_front()) if (pred(range.front())) break; return range; } template inline auto find_if(F &&func) { return [func = forward(func)](auto &&obj) mutable { return find_if(forward(obj), forward(func)); }; } template inline R find_if_not(R range, P pred) { for (; !range.empty(); range.pop_front()) if (!pred(range.front())) break; return range; } template inline auto find_if_not(F &&func) { return [func = forward(func)](auto &&obj) mutable { return find_if_not(forward(obj), forward(func)); }; } template inline R1 find_one_of_cmp(R1 range, R2 values, C compare) { for (; !range.empty(); range.pop_front()) for (R2 rv = values; !rv.empty(); rv.pop_front()) if (compare(range.front(), rv.front())) return range; return range; } template inline auto find_one_of_cmp(R &&values, C &&compare) { return [values = forward(values), compare = forward(compare)](auto &&obj) mutable { return find_one_of_cmp(forward(obj), forward(values), forward(compare)); }; } template inline R1 find_one_of(R1 range, R2 values) { for (; !range.empty(); range.pop_front()) for (R2 rv = values; !rv.empty(); rv.pop_front()) if (range.front() == rv.front()) return range; return range; } template inline auto find_one_of(R &&values) { return [values = forward(values)](auto &&obj) mutable { return find_one_of(forward(obj), forward(values)); }; } template inline RangeSize count(R range, const T &v) { RangeSize ret = 0; for (; !range.empty(); range.pop_front()) if (range.front() == v) ++ret; return ret; } template inline auto count(T &&v) { return [v = forward(v)](auto &&obj) mutable { return count(forward(obj), forward(v)); }; } template inline RangeSize count_if(R range, P pred) { RangeSize ret = 0; for (; !range.empty(); range.pop_front()) if (pred(range.front())) ++ret; return ret; } template inline auto count_if(F &&func) { return [func = forward(func)](auto &&obj) mutable { return count_if(forward(obj), forward(func)); }; } template inline RangeSize count_if_not(R range, P pred) { RangeSize ret = 0; for (; !range.empty(); range.pop_front()) if (!pred(range.front())) ++ret; return ret; } template inline auto count_if_not(F &&func) { return [func = forward(func)](auto &&obj) mutable { return count_if_not(forward(obj), forward(func)); }; } template inline bool equal(R range1, R range2) { for (; !range1.empty(); range1.pop_front()) { if (range2.empty() || (range1.front() != range2.front())) return false; range2.pop_front(); } return range2.empty(); } template inline auto equal(R &&range) { return [range = forward(range)](auto &&obj) mutable { return equal(forward(obj), forward(range)); }; } template R slice_until(R range1, R range2) { return range1.slice(0, range1.distance_front(range2)); } template inline auto slice_until(R &&range) { return [range = forward(range)](auto &&obj) mutable { return slice_until(forward(obj), forward(range)); }; } /* algos that modify ranges or work with output ranges */ template inline R2 copy(R1 irange, R2 orange) { for (; !irange.empty(); irange.pop_front()) orange.put(irange.front()); return orange; } template inline R2 copy_if(R1 irange, R2 orange, P pred) { for (; !irange.empty(); irange.pop_front()) if (pred(irange.front())) orange.put(irange.front()); return orange; } template inline R2 copy_if_not(R1 irange, R2 orange, P pred) { for (; !irange.empty(); irange.pop_front()) if (!pred(irange.front())) orange.put(irange.front()); return orange; } template inline R2 move(R1 irange, R2 orange) { for (; !irange.empty(); irange.pop_front()) orange.put(move(irange.front())); return orange; } template inline void reverse(R range) { while (!range.empty()) { detail::swap_adl(range.front(), range.back()); range.pop_front(); range.pop_back(); } } template inline R2 reverse_copy(R1 irange, R2 orange) { for (; !irange.empty(); irange.pop_back()) orange.put(irange.back()); return orange; } template inline void fill(R range, const T &v) { for (; !range.empty(); range.pop_front()) range.front() = v; } template inline void generate(R range, F gen) { for (; !range.empty(); range.pop_front()) range.front() = gen(); } template inline Pair swap_ranges(R1 range1, R2 range2) { while (!range1.empty() && !range2.empty()) { detail::swap_adl(range1.front(), range2.front()); range1.pop_front(); range2.pop_front(); } return ostd::make_pair(range1, range2); } template inline void iota(R range, T value) { for (; !range.empty(); range.pop_front()) range.front() = value++; } template inline T foldl(R range, T init) { for (; !range.empty(); range.pop_front()) init = init + range.front(); return init; } template inline T foldl_f(R range, T init, F func) { for (; !range.empty(); range.pop_front()) init = func(init, range.front()); return init; } template inline auto foldl(T &&init) { return [init = forward(init)](auto &&obj) mutable { return foldl(forward(obj), forward(init)); }; } template inline auto foldl_f(T &&init, F &&func) { return [init = forward(init), func = forward(func)](auto &&obj) mutable { return foldl_f(forward(obj), forward(init), forward(func)); }; } template inline T foldr(R range, T init) { for (; !range.empty(); range.pop_back()) init = init + range.back(); return init; } template inline T foldr_f(R range, T init, F func) { for (; !range.empty(); range.pop_back()) init = func(init, range.back()); return init; } template inline auto foldr(T &&init) { return [init = forward(init)](auto &&obj) mutable { return foldr(forward(obj), forward(init)); }; } template inline auto foldr_f(T &&init, F &&func) { return [init = forward(init), func = forward(func)](auto &&obj) mutable { return foldr_f(forward(obj), forward(init), forward(func)); }; } template struct MapRange: InputRange< MapRange, RangeCategory, R, R, RangeSize > { private: T p_range; F p_func; public: MapRange() = delete; template MapRange(const T &range, FF &&func): p_range(range), p_func(forward(func)) {} MapRange(const MapRange &it): p_range(it.p_range), p_func(it.p_func) {} MapRange(MapRange &&it): p_range(move(it.p_range)), p_func(move(it.p_func)) {} MapRange &operator=(const MapRange &v) { p_range = v.p_range; p_func = v.p_func; return *this; } MapRange &operator=(MapRange &&v) { p_range = move(v.p_range); p_func = move(v.p_func); return *this; } bool empty() const { return p_range.empty(); } RangeSize size() const { return p_range.size(); } bool equals_front(const MapRange &r) const { return p_range.equals_front(r.p_range); } bool equals_back(const MapRange &r) const { return p_range.equals_front(r.p_range); } RangeDifference distance_front(const MapRange &r) const { return p_range.distance_front(r.p_range); } RangeDifference distance_back(const MapRange &r) const { return p_range.distance_back(r.p_range); } bool pop_front() { return p_range.pop_front(); } bool pop_back() { return p_range.pop_back(); } bool push_front() { return p_range.pop_front(); } bool push_back() { return p_range.push_back(); } RangeSize pop_front_n(RangeSize n) { p_range.pop_front_n(n); } RangeSize pop_back_n(RangeSize n) { p_range.pop_back_n(n); } RangeSize push_front_n(RangeSize n) { return p_range.push_front_n(n); } RangeSize push_back_n(RangeSize n) { return p_range.push_back_n(n); } R front() const { return p_func(p_range.front()); } R back() const { return p_func(p_range.back()); } R operator[](RangeSize idx) const { return p_func(p_range[idx]); } MapRange slice(RangeSize start, RangeSize end) { return MapRange(p_range.slice(start, end), p_func); } }; namespace detail { template using MapReturnType = decltype(declval()(declval>())); } template inline MapRange> map(R range, F func) { return MapRange>(range, move(func)); } template inline auto map(F &&func) { return [func = forward(func)](auto &&obj) mutable { return map(forward(obj), forward(func)); }; } template struct FilterRange: InputRange< FilterRange, CommonType, ForwardRangeTag>, RangeValue, RangeReference, RangeSize > { private: T p_range; F p_pred; void advance_valid() { while (!p_range.empty() && !p_pred(front())) p_range.pop_front(); } public: FilterRange() = delete; template FilterRange(const T &range, P &&pred): p_range(range), p_pred(forward

(pred)) { advance_valid(); } FilterRange(const FilterRange &it): p_range(it.p_range), p_pred(it.p_pred) { advance_valid(); } FilterRange(FilterRange &&it): p_range(move(it.p_range)), p_pred(move(it.p_pred)) { advance_valid(); } FilterRange &operator=(const FilterRange &v) { p_range = v.p_range; p_pred = v.p_pred; advance_valid(); return *this; } FilterRange &operator=(FilterRange &&v) { p_range = move(v.p_range); p_pred = move(v.p_pred); advance_valid(); return *this; } bool empty() const { return p_range.empty(); } bool equals_front(const FilterRange &r) const { return p_range.equals_front(r.p_range); } bool pop_front() { bool ret = p_range.pop_front(); advance_valid(); return ret; } RangeReference front() const { return p_range.front(); } }; namespace detail { template using FilterPred = EnableIf()(declval>())), bool >, P>; } template inline FilterRange> filter(R range, P pred) { return FilterRange(range, pred); } template inline auto filter(F &&func) { return [func = forward(func)](auto &&obj) mutable { return filter(forward(obj), forward(func)); }; } } /* namespace ostd */ #endif