/* Algorithms for OctaSTD. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OCTA_ALGORITHM_HH #define OCTA_ALGORITHM_HH #include #include "octa/functional.hh" #include "octa/range.hh" #include "octa/utility.hh" #include "octa/initializer_list.hh" namespace octa { /* partitioning */ template R partition(R range, U pred) { R ret = range; for (; !range.empty(); range.pop_front()) { if (pred(range.front())) { octa::swap(range.front(), ret.front()); ret.pop_front(); } } return ret; } template 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; } /* sorting */ namespace detail { template void insort(R range, C compare) { octa::RangeSize rlen = range.size(); for (octa::RangeSize i = 1; i < rlen; ++i) { octa::RangeSize j = i; octa::RangeValue v(octa::move(range[i])); while (j > 0 && !compare(range[j - 1], v)) { range[j] = range[j - 1]; --j; } range[j] = octa::move(v); } } template void hs_sift_down(R range, octa::RangeSize s, octa::RangeSize e, C compare) { octa::RangeSize r = s; while ((r * 2 + 1) <= e) { octa::RangeSize ch = r * 2 + 1; octa::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) { octa::swap(range[r], range[sw]); r = sw; } else return; } } template void heapsort(R range, C compare) { octa::RangeSize len = range.size(); octa::RangeSize st = (len - 2) / 2; for (;;) { octa::detail::hs_sift_down(range, st, len - 1, compare); if (st-- == 0) break; } octa::RangeSize e = len - 1; while (e > 0) { octa::swap(range[e], range[0]); --e; octa::detail::hs_sift_down(range, 0, e, compare); } } template void introloop(R range, C compare, RangeSize depth) { if (range.size() <= 10) { octa::detail::insort(range, compare); return; } if (depth == 0) { octa::detail::heapsort(range, compare); return; } octa::swap(range[range.size() / 2], range.back()); octa::RangeSize pi = 0; R pr = range; pr.pop_back(); for (; !pr.empty(); pr.pop_front()) { if (compare(pr.front(), range.back())) octa::swap(pr.front(), range[pi++]); } octa::swap(range[pi], range.back()); octa::detail::introloop(range.slice(0, pi), compare, depth - 1); octa::detail::introloop(range.slice(pi + 1, range.size()), compare, depth - 1); } template void introsort(R range, C compare) { octa::detail::introloop(range, compare, octa::RangeSize(2 * (log(range.size()) / log(2)))); } } /* namespace detail */ template void sort(R range, C compare) { octa::detail::introsort(range, compare); } template void sort(R range) { sort(range, octa::Less>()); } /* min/max(_element) */ template inline const T &min(const T &a, const T &b) { return (a < b) ? a : b; } template inline const T &min(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(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 (octa::min(r.front(), range.front()) == range.front()) r = range; return r; } template inline R min_element(R range, C compare) { R r = range; for (; !range.empty(); range.pop_front()) if (octa::min(r.front(), range.front(), compare) == range.front()) r = range; return r; } template inline R max_element(R range) { R r = range; for (; !range.empty(); range.pop_front()) if (octa::max(r.front(), range.front()) == range.front()) r = range; return r; } template inline R max_element(R range, C compare) { R r = range; for (; !range.empty(); range.pop_front()) if (octa::max(r.front(), range.front(), compare) == range.front()) r = range; return r; } template inline T min(std::initializer_list il) { return octa::min_element(octa::iter(il)).front(); } template inline T min(std::initializer_list il, C compare) { return octa::min_element(octa::iter(il), compare).front(); } template inline T max(std::initializer_list il) { return octa::max_element(octa::iter(il)).front(); } template inline T max(std::initializer_list il, C compare) { return octa::max_element(octa::iter(il), compare).front(); } /* clamp */ template inline T clamp(const T &v, const U &lo, const U &hi) { return octa::max(T(lo), octa::min(v, T(hi))); } template inline T clamp(const T &v, const U &lo, const U &hi, C compare) { return octa::max(T(lo), octa::min(v, T(hi), compare), compare); } /* algos that don't change the range */ template F for_each(R range, F func) { for (; !range.empty(); range.pop_front()) func(range.front()); return octa::move(func); } template bool all_of(R range, P pred) { for (; !range.empty(); range.pop_front()) if (!pred(range.front())) return false; return true; } template bool any_of(R range, P pred) { for (; !range.empty(); range.pop_front()) if (pred(range.front())) return true; return false; } template bool none_of(R range, P pred) { for (; !range.empty(); range.pop_front()) if (pred(range.front())) return false; return true; } template R find(R range, const T &v) { for (; !range.empty(); range.pop_front()) if (range.front() == v) break; return range; } template R find_if(R range, P pred) { for (; !range.empty(); range.pop_front()) if (pred(range.front())) break; return range; } template R find_if_not(R range, P pred) { for (; !range.empty(); range.pop_front()) if (!pred(range.front())) break; return range; } template RangeSize count(R range, const T &v) { RangeSize ret = 0; for (; !range.empty(); range.pop_front()) if (range.front() == v) ++ret; return ret; } template RangeSize count_if(R range, P pred) { RangeSize ret = 0; for (; !range.empty(); range.pop_front()) if (pred(range.front())) ++ret; return ret; } template 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 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(); } /* algos that modify ranges or work with output ranges */ template R2 copy(R1 irange, R2 orange) { for (; !irange.empty(); irange.pop_front()) orange.put(irange.front()); return orange; } template 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 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 R2 move(R1 irange, R2 orange) { for (; !irange.empty(); irange.pop_front()) orange.put(octa::move(irange.front())); return orange; } template void reverse(R range) { while (!range.empty()) { octa::swap(range.front(), range.back()); range.pop_front(); range.pop_back(); } } template R2 reverse_copy(R1 irange, R2 orange) { for (; !irange.empty(); irange.pop_back()) orange.put(irange.back()); return orange; } template void fill(R range, const T &v) { for (; !range.empty(); range.pop_front()) range.front() = v; } template void generate(R range, F gen) { for (; !range.empty(); range.pop_front()) range.front() = gen(); } template octa::Pair swap_ranges(R1 range1, R2 range2) { while (!range1.empty() && !range2.empty()) { octa::swap(range1.front(), range2.front()); range1.pop_front(); range2.pop_front(); } return octa::make_pair(range1, range2); } template void iota(R range, T value) { for (; !range.empty(); range.pop_front()) range.front() = value++; } template T foldl(R range, T init) { for (; !range.empty(); range.pop_front()) init = init + range.front(); return init; } template T foldl(R range, T init, F func) { for (; !range.empty(); range.pop_front()) init = func(init, range.front()); return init; } template T foldr(R range, T init) { for (; !range.empty(); range.pop_back()) init = init + range.back(); return init; } template T foldr(R range, T init, F func) { for (; !range.empty(); range.pop_back()) init = func(init, range.back()); return init; } template struct MapRange: InputRange< MapRange, octa::RangeCategory, R, R, octa::RangeSize > { private: T p_range; octa::FunctionMakeDefaultConstructible p_func; public: MapRange() = delete; MapRange(const T &range, const F &func): p_range(range), p_func(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(); } octa::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); } octa::RangeDifference distance_front(const MapRange &r) const { return p_range.distance_front(r.p_range); } octa::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(); } octa::RangeSize pop_front_n(octa::RangeSize n) { p_range.pop_front_n(n); } octa::RangeSize pop_back_n(octa::RangeSize n) { p_range.pop_back_n(n); } octa::RangeSize push_front_n(octa::RangeSize n) { return p_range.push_front_n(n); } octa::RangeSize push_back_n(octa::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[](octa::RangeSize idx) const { return p_func(p_range[idx]); } MapRange slice(octa::RangeSize start, octa::RangeSize end) { return MapRange(p_range.slice(start, end), p_func); } }; namespace detail { template using MapReturnType = decltype(declval()(octa::declval>())); } template MapRange> map(R range, F func) { return octa::MapRange>(range, func); } template struct FilterRange: InputRange< FilterRange, octa::CommonType, octa::ForwardRangeTag>, octa::RangeValue, octa::RangeReference, octa::RangeSize > { private: T p_range; octa::FunctionMakeDefaultConstructible p_pred; void advance_valid() { while (!p_range.empty() && !p_pred(front())) p_range.pop_front(); } public: FilterRange() = delete; template FilterRange(const T &range, const P &pred): p_range(range), p_pred(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; } octa::RangeReference front() const { return p_range.front(); } }; namespace detail { template using FilterPred = octa::EnableIf()(octa::declval< octa::RangeReference >())), bool >::value, P>; } template FilterRange> filter(R range, P pred) { return octa::FilterRange(range, pred); } } /* namespace octa */ #endif