/* Algorithms for libostd. * * This file is part of libostd. See COPYING.md for futher information. */ #ifndef OSTD_ALGORITHM_HH #define OSTD_ALGORITHM_HH #include #include #include #include #include #include "ostd/range.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())) { using std::swap; swap(range.front(), ret.front()); ret.pop_front(); } } return ret; } template inline auto partition(F &&func) { return [func = std::forward(func)](auto &&obj) mutable { return partition( std::forward(obj), std::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 = std::forward(func)](auto &&obj) mutable { return is_partitioned( std::forward(obj), std::forward(func) ); }; } /* sorting */ namespace detail { template static void insort(R range, C &compare) { range_size_t rlen = range.size(); for (range_size_t i = 1; i < rlen; ++i) { range_size_t j = i; range_value_t v{std::move(range[i])}; while (j > 0 && !compare(range[j - 1], v)) { range[j] = std::move(range[j - 1]); --j; } range[j] = std::move(v); } } template static void hs_sift_down( R range, range_size_t s, range_size_t e, C &compare ) { range_size_t r = s; while ((r * 2 + 1) <= e) { range_size_t ch = r * 2 + 1; range_size_t 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) { using std::swap; swap(range[r], range[sw]); r = sw; } else { return; } } } template static void heapsort(R range, C &compare) { range_size_t len = range.size(); range_size_t st = (len - 2) / 2; for (;;) { detail::hs_sift_down(range, st, len - 1, compare); if (st-- == 0) { break; } } range_size_t e = len - 1; while (e > 0) { using std::swap; swap(range[e], range[0]); --e; detail::hs_sift_down(range, 0, e, compare); } } template static void introloop(R range, C &compare, range_size_t depth) { using std::swap; if (range.size() <= 10) { detail::insort(range, compare); return; } if (depth == 0) { detail::heapsort(range, compare); return; } swap(range[range.size() / 2], range.back()); range_size_t pi = 0; R pr = range; pr.pop_back(); for (; !pr.empty(); pr.pop_front()) { if (compare(pr.front(), range.back())) { swap(pr.front(), range[pi++]); } } swap(range[pi], range.back()); detail::introloop(range.slice(0, pi), compare, depth - 1); detail::introloop(range.slice(pi + 1), compare, depth - 1); } template inline void introsort(R range, C &compare) { detail::introloop( range, compare, static_cast>(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 = std::forward(compare)](auto &&obj) mutable { return sort_cmp( std::forward(obj), std::forward(compare) ); }; } template inline R sort(R range) { return sort_cmp(range, std::less>()); } inline auto sort() { return [](auto &&obj) { return sort(std::forward(obj)); }; } /* min/max(_element) */ template inline R min_element(R range) { R r = range; for (; !range.empty(); range.pop_front()) { if (std::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 (std::min(r.front(), range.front(), compare) == range.front()) { r = range; } } return r; } inline auto min_element() { return [](auto &&obj) { return min_element(std::forward(obj)); }; } template inline auto min_element_cmp(C &&compare) { return [compare = std::forward(compare)](auto &&obj) mutable { return min_element_cmp( std::forward(obj), std::forward(compare) ); }; } template inline R max_element(R range) { R r = range; for (; !range.empty(); range.pop_front()) { if (std::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 (std::max(r.front(), range.front(), compare) == range.front()) { r = range; } } return r; } inline auto max_element() { return [](auto &&obj) { return max_element(std::forward(obj)); }; } template inline auto max_element_cmp(C &&compare) { return [compare = std::forward(compare)](auto &&obj) mutable { return max_element_cmp( std::forward(obj), std::forward(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 = std::forward(range)](auto &&obj) mutable { return lexicographical_compare( std::forward(obj), std::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 = std::forward(range), compare = std::forward(compare) ](auto &&obj) mutable { return lexicographical_compare_cmp( std::forward(obj), std::forward(range), std::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 std::move(func); } template inline auto for_each(F &&func) { return [func = std::forward(func)](auto &&obj) mutable { return for_each(std::forward(obj), std::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 = std::forward(func)](auto &&obj) mutable { return all_of(std::forward(obj), std::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 = std::forward(func)](auto &&obj) mutable { return any_of(std::forward(obj), std::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 = std::forward(func)](auto &&obj) mutable { return none_of(std::forward(obj), std::forward(func)); }; } template inline R find(R range, T const &v) { for (; !range.empty(); range.pop_front()) { if (range.front() == v) { break; } } return range; } template inline auto find(T &&v) { return [v = std::forward(v)](auto &&obj) mutable { return find(std::forward(obj), std::forward(v)); }; } template inline R find_last(R range, T const &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 = std::forward(v)](auto &&obj) mutable { return find_last(std::forward(obj), std::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 = std::forward(func)](auto &&obj) mutable { return find_if(std::forward(obj), std::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 = std::forward(func)](auto &&obj) mutable { return find_if_not( std::forward(obj), std::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 = std::forward(values), compare = std::forward(compare) ](auto &&obj) mutable { return find_one_of_cmp( std::forward(obj), std::forward(values), std::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 = std::forward(values)](auto &&obj) mutable { return find_one_of( std::forward(obj), std::forward(values) ); }; } template inline range_size_t count(R range, T const &v) { range_size_t ret = 0; for (; !range.empty(); range.pop_front()) { if (range.front() == v) { ++ret; } } return ret; } template inline auto count(T &&v) { return [v = std::forward(v)](auto &&obj) mutable { return count(std::forward(obj), std::forward(v)); }; } template inline range_size_t count_if(R range, P pred) { range_size_t ret = 0; for (; !range.empty(); range.pop_front()) { if (pred(range.front())) { ++ret; } } return ret; } template inline auto count_if(F &&func) { return [func = std::forward(func)](auto &&obj) mutable { return count_if(std::forward(obj), std::forward(func)); }; } template inline range_size_t count_if_not(R range, P pred) { range_size_t 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 = std::forward(func)](auto &&obj) mutable { return count_if_not( std::forward(obj), std::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 = std::forward(range)](auto &&obj) mutable { return equal(std::forward(obj), std::forward(range)); }; } /* algos that modify ranges or work with output ranges */ template inline R2 copy(R1 irange, R2 orange) { range_put_all(orange, irange); 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(std::move(irange.front())); } return orange; } template inline void reverse(R range) { while (!range.empty()) { using std::swap; swap(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, T const &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 std::pair swap_ranges(R1 range1, R2 range2) { while (!range1.empty() && !range2.empty()) { using std::swap; swap(range1.front(), range2.front()); range1.pop_front(); range2.pop_front(); } return std::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 = std::forward(init)](auto &&obj) mutable { return foldl(std::forward(obj), std::forward(init)); }; } template inline auto foldl_f(T &&init, F &&func) { return [ init = std::forward(init), func = std::forward(func) ](auto &&obj) mutable { return foldl_f( std::forward(obj), std::forward(init), std::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 = std::forward(init)](auto &&obj) mutable { return foldr(std::forward(obj), std::forward(init)); }; } template inline auto foldr_f(T &&init, F &&func) { return [ init = std::forward(init), func = std::forward(func) ](auto &&obj) mutable { return foldr_f( std::forward(obj), std::forward(init), std::forward(func) ); }; } template struct map_range: input_range> { using range_category = std::common_type_t< range_category_t, finite_random_access_range_tag >; using value_type = R; using reference = R; using size_type = range_size_t; using difference_type = range_difference_t; private: T p_range; std::decay_t p_func; public: map_range() = delete; template map_range(T const &range, FF &&func): p_range(range), p_func(std::forward(func)) {} map_range(map_range const &it): p_range(it.p_range), p_func(it.p_func) {} map_range(map_range &&it): p_range(std::move(it.p_range)), p_func(std::move(it.p_func)) {} map_range &operator=(map_range const &v) { p_range = v.p_range; p_func = v.p_func; return *this; } map_range &operator=(map_range &&v) { p_range = std::move(v.p_range); p_func = std::move(v.p_func); return *this; } bool empty() const { return p_range.empty(); } size_type size() const { return p_range.size(); } void pop_front() { p_range.pop_front(); } void pop_back() { p_range.pop_back(); } R front() const { return p_func(p_range.front()); } R back() const { return p_func(p_range.back()); } R operator[](size_type idx) const { return p_func(p_range[idx]); } map_range slice(size_type start, size_type end) const { return map_range(p_range.slice(start, end), p_func); } map_range slice(size_type start) const { return slice(start, size()); } }; namespace detail { template using MapReturnType = decltype( std::declval()(std::declval>()) ); } template inline map_range> map(R range, F func) { return map_range>(range, std::move(func)); } template inline auto map(F &&func) { return [func = std::forward(func)](auto &&obj) mutable { return map(std::forward(obj), std::forward(func)); }; } template struct filter_range: input_range> { using range_category = std::common_type_t< range_category_t, forward_range_tag >; using value_type = range_value_t; using reference = range_reference_t; using size_type = range_size_t; using difference_type = range_difference_t; private: T p_range; std::decay_t p_pred; void advance_valid() { while (!p_range.empty() && !p_pred(front())) { p_range.pop_front(); } } public: filter_range() = delete; template filter_range(T const &range, P &&pred): p_range(range), p_pred(std::forward

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