/* Algorithms for OctaSTD. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OCTA_ALGORITHM_H #define OCTA_ALGORITHM_H #include #include "octa/functional.h" #include "octa/range.h" #include "octa/utility.h" #include "octa/initializer_list.h" namespace octa { template using __OctaRangeSize = typename RangeTraits::size_type; /* partitioning */ template R partition(R range, U pred) { R ret = range; for (; !range.empty(); range.pop_first()) { if (pred(range.first())) { swap(range.first(), ret.first()); ret.pop_first(); } } return ret; } template bool is_partitioned(R range, P pred) { for (; !range.empty() && pred(range.first()); range.pop_first()); for (; !range.empty(); range.pop_first()) if (pred(range.first())) return false; return true; } /* insertion sort */ template void insertion_sort(R range, C compare) { __OctaRangeSize rlen = range.length(); for (__OctaRangeSize i = 1; i < rlen; ++i) { __OctaRangeSize j = i, v = range[i]; while (j > 0 && !compare(range[j - 1], v)) { range[j] = range[j - 1]; --j; } range[j] = v; } } template void insertion_sort(R range) { insertion_sort(range, Less::value_type>()); } /* sort (introsort) */ template struct __OctaUnaryCompare { const T &val; U comp; bool operator()(const T &v) const { return comp(v, val); } }; template void __octa_hs_sift_down(R range, __OctaRangeSize s, __OctaRangeSize e, C compare) { __OctaRangeSize r = s; while ((r * 2 + 1) <= e) { __OctaRangeSize ch = r * 2 + 1; __OctaRangeSize 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) { swap(range[r], range[sw]); r = sw; } else return; } } template void __octa_heapsort(R range, C compare) { __OctaRangeSize len = range.length(); __OctaRangeSize st = (len - 2) / 2; for (;;) { __octa_hs_sift_down(range, st, len - 1, compare); if (st-- == 0) break; } __OctaRangeSize e = len - 1; while (e > 0) { swap(range[e], range[0]); --e; __octa_hs_sift_down(range, 0, e, compare); } } template void __octa_introloop(R range, C compare, __OctaRangeSize depth) { if (range.length() <= 10) { insertion_sort(range, compare); return; } if (depth == 0) { __octa_heapsort(range, compare); return; } typename RangeTraits::reference p = range[range.length() / 2]; swap(p, range.last()); R r = partition(range, __OctaUnaryCompare{ p, compare }); R l = range.slice(0, range.length() - r.length()); swap(r.first(), r.last()); __octa_introloop(l, compare, depth - 1); __octa_introloop(r, compare, depth - 1); } template void __octa_introsort(R range, C compare) { __octa_introloop(range, compare, __OctaRangeSize(2 * (log(range.length()) / log(2)))); } template void sort(R range, C compare) { __octa_introsort(range, compare); } template void sort(R range) { sort(range, Less::value_type>()); } /* 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_first()) if (min(r.first(), range.first()) == range.first()) r = range; return r; } template inline R min_element(R range, C compare) { R r = range; for (; !range.empty(); range.pop_first()) if (min(r.first(), range.first(), compare) == range.first()) r = range; return r; } template inline R max_element(R range) { R r = range; for (; !range.empty(); range.pop_first()) if (max(r.first(), range.first()) == range.first()) r = range; return r; } template inline R max_element(R range, C compare) { R r = range; for (; !range.empty(); range.pop_first()) if (max(r.first(), range.first(), compare) == range.first()) r = range; return r; } template inline T min(InitializerList il) { return min_element(il.range()).first(); } template inline T min(InitializerList il, C compare) { return min_element(il.range(), compare).first(); } template inline T max(InitializerList il) { return max_element(il.range()).first(); } template inline T max(InitializerList il, C compare) { return max_element(il.range(), compare).first(); } /* clamp */ template inline T clamp(const T &v, const U &lo, const U &hi) { return max(T(lo), min(v, T(hi))); } template inline T clamp(const T &v, const U &lo, const U &hi, C compare) { return max(T(lo), 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_first()) func(range.first()); return move(func); } template bool all_of(R range, P pred) { for (; !range.empty(); range.pop_first()) if (!pred(range.first())) return false; return true; } template bool any_of(R range, P pred) { for (; !range.empty(); range.pop_first()) if (pred(range.first())) return true; return false; } template bool none_of(R range, P pred) { for (; !range.empty(); range.pop_first()) if (pred(range.first())) return false; return true; } template R find(R range, const T &v) { for (; !range.empty(); range.pop_first()) if (range.first() == v) break; return range; } template R find_if(R range, P pred) { for (; !range.empty(); range.pop_first()) if (pred(range.first())) break; return range; } template R find_if_not(R range, P pred) { for (; !range.empty(); range.pop_first()) if (!pred(range.first())) break; return range; } template __OctaRangeSize count(R range, const T &v) { __OctaRangeSize ret = 0; for (; !range.empty(); range.pop_first()) if (range.first() == v) ++ret; return ret; } template __OctaRangeSize count_if(R range, P pred) { __OctaRangeSize ret = 0; for (; !range.empty(); range.pop_first()) if (pred(range.first())) ++ret; return ret; } template __OctaRangeSize count_if_not(R range, P pred) { __OctaRangeSize ret = 0; for (; !range.empty(); range.pop_first()) if (!pred(range.first())) ++ret; return ret; } template bool equal(R range1, R range2) { for (; !range1.empty(); range1.pop_first()) { if (range2.empty() || (range1.first() != range2.first())) return false; range2.pop_first(); } return range2.empty(); } /* algos that modify ranges or work with output ranges */ template R2 copy(R1 irange, R2 orange) { for (; !irange.empty(); irange.pop_first()) orange.put(irange.first()); return orange; } template R2 copy_if(R1 irange, R2 orange, P pred) { for (; !irange.empty(); irange.pop_first()) if (pred(irange.first())) orange.put(irange.first()); return orange; } template R2 copy_if_not(R1 irange, R2 orange, P pred) { for (; !irange.empty(); irange.pop_first()) if (!pred(irange.first())) orange.put(irange.first()); return orange; } template R2 move(R1 irange, R2 orange) { for (; !irange.empty(); irange.pop_first()) orange.put(move(irange.first())); return orange; } template void reverse(R range) { while (!range.empty()) { swap(range.first(), range.last()); range.pop_first(); range.pop_last(); } } template R2 reverse_copy(R1 irange, R2 orange) { for (; !irange.empty(); irange.pop_last()) orange.put(irange.last()); return orange; } template void fill(R range, const T &v) { for (; !range.empty(); range.pop_first()) range.first() = v; } template void generate(R range, F gen) { for (; !range.empty(); range.pop_first()) range.first() = gen(); } template R2 swap_ranges(R1 range1, R2 range2) { for (; !range1.empty(); range1.pop_first()) { swap(range1.first(), range2.first()); range2.pop_first(); } return range2; } template void iota(R range, T value) { for (; !range.empty(); range.pop_first()) range.first() = value++; } } #endif