diff --git a/octa/algorithm.h b/octa/algorithm.h index eab962e..6467fe3 100644 --- a/octa/algorithm.h +++ b/octa/algorithm.h @@ -15,566 +15,567 @@ namespace octa { - /* partitioning */ +/* 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<_R> __rlen = __range.size(); - for (octa::RangeSize<_R> __i = 1; __i < __rlen; ++__i) { - octa::RangeSize<_R> __j = __i; - octa::RangeReference<_R> __v = __range[__i]; - while (__j > 0 && !__compare(__range[__j - 1], __v)) { - __range[__j] = __range[__j - 1]; - --__j; - } - __range[__j] = __v; - } - } - - template - struct UnaryCompare { - const _T &__val; - _U __comp; - bool operator()(const _T &__v) const { return __comp(__v, __val); } - }; - - template - void hs_sift_down(_R __range, octa::RangeSize<_R> __s, - octa::RangeSize<_R> __e, _C __compare) { - octa::RangeSize<_R> __r = __s; - while ((__r * 2 + 1) <= __e) { - octa::RangeSize<_R> __ch = __r * 2 + 1; - octa::RangeSize<_R> __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<_R> __len = __range.size(); - octa::RangeSize<_R> __st = (__len - 2) / 2; - for (;;) { - octa::detail::hs_sift_down(__range, __st, __len - 1, __compare); - if (__st-- == 0) break; - } - octa::RangeSize<_R> __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<_R> __depth) { - if (__range.size() <= 10) { - octa::detail::insort(__range, __compare); - return; - } - if (__depth == 0) { - octa::detail::heapsort(__range, __compare); - return; - } - octa::RangeReference<_R> __p = __range[__range.size() / 2]; - octa::swap(__p, __range.back()); - _R __r = octa::partition(__range, - octa::detail::UnaryCompare{ __p, __compare }); - _R __l = __range.slice(0, __range.size() - __r.size()); - octa::swap(__r.front(), __r.back()); - octa::detail::introloop(__l, __compare, __depth - 1); - octa::detail::introloop(__r, __compare, __depth - 1); - } - - template - void introsort(_R __range, _C __compare) { - octa::detail::introloop(__range, __compare, octa::RangeSize<_R>(2 - * (log(__range.size()) / log(2)))); +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 sort(_R __range, _C __compare) { - octa::detail::introsort(__range, __compare); + void insort(_R range, _C compare) { + octa::RangeSize<_R> rlen = range.size(); + for (octa::RangeSize<_R> i = 1; i < rlen; ++i) { + octa::RangeSize<_R> j = i; + octa::RangeReference<_R> v = range[i]; + while (j > 0 && !compare(range[j - 1], v)) { + range[j] = range[j - 1]; + --j; + } + range[j] = v; + } } - 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<_T> __il) { - return octa::min_element(octa::each(__il)).front(); - } - template - inline _T min(std::initializer_list<_T> __il, _C __compare) { - return octa::min_element(octa::each(__il), __compare).front(); - } - - template - inline _T max(std::initializer_list<_T> __il) { - return octa::max_element(octa::each(__il)).front(); - } - - template - inline _T max(std::initializer_list<_T> __il, _C __compare) { - return octa::max_element(octa::each(__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<_R> count(_R __range, const _T &__v) { - RangeSize<_R> __ret = 0; - for (; !__range.empty(); __range.pop_front()) - if (__range.front() == __v) - ++__ret; - return __ret; - } - - template - RangeSize<_R> count_if(_R __range, _P __pred) { - RangeSize<_R> __ret = 0; - for (; !__range.empty(); __range.pop_front()) - if (__pred(__range.front())) - ++__ret; - return __ret; - } - - template - RangeSize<_R> count_if_not(_R __range, _P __pred) { - RangeSize<_R> __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<_R1, _R2> 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<_T, _R>, octa::RangeCategory<_T>, _R, _R, octa::RangeSize<_T> - > { - private: - _T __range; - octa::Function<_R(octa::RangeReference<_T>)> __func; - - public: - MapRange(): __range(), __func() {} - template - MapRange(const _T &__range, const _F &__func): - __range(__range), __func(__func) {} - MapRange(const MapRange &__it): - __range(__it.__range), __func(__it.__func) {} - MapRange(MapRange &&__it): - __range(move(__it.__range)), __func(move(__it.__func)) {} - - MapRange &operator=(const MapRange &__v) { - __range = __v.__range; - __func = __v.__func; - return *this; - } - MapRange &operator=(MapRange &&__v) { - __range = move(__v.__range); - __func = move(__v.__func); - return *this; - } - - bool empty() const { return __range.empty(); } - octa::RangeSize<_T> size() const { return __range.size(); } - - bool equals_front(const MapRange &__r) const { - return __range.equals_front(__r.__range); - } - bool equals_back(const MapRange &__r) const { - return __range.equals_front(__r.__range); - } - - octa::RangeDifference<_T> distance_front(const MapRange &__r) const { - return __range.distance_front(__r.__range); - } - octa::RangeDifference<_T> distance_back(const MapRange &__r) const { - return __range.distance_back(__r.__range); - } - - bool pop_front() { return __range.pop_front(); } - bool pop_back() { return __range.pop_back(); } - - bool push_front() { return __range.pop_front(); } - bool push_back() { return __range.push_back(); } - - octa::RangeSize<_T> pop_front_n(octa::RangeSize<_T> __n) { - __range.pop_front_n(__n); - } - octa::RangeSize<_T> pop_back_n(octa::RangeSize<_T> __n) { - __range.pop_back_n(__n); - } - - octa::RangeSize<_T> push_front_n(octa::RangeSize<_T> __n) { - return __range.push_front_n(__n); - } - octa::RangeSize<_T> push_back_n(octa::RangeSize<_T> __n) { - return __range.push_back_n(__n); - } - - _R front() const { return __func(__range.front()); } - _R back() const { return __func(__range.back()); } - - _R operator[](octa::RangeSize<_T> __idx) const { - return __func(__range[__idx]); - } - - MapRange<_T, _R> slice(octa::RangeSize<_T> __start, - octa::RangeSize<_T> __end) { - return MapRange<_T, _R>(__range.slice(__start, __end), __func); - } + struct UnaryCompare { + const _T &val; + _U comp; + bool operator()(const _T &v) const { return comp(v, val); } }; - namespace detail { - template using MapReturnType - = decltype(declval<_F>()(octa::declval>())); + template + void hs_sift_down(_R range, octa::RangeSize<_R> s, + octa::RangeSize<_R> e, _C compare) { + octa::RangeSize<_R> r = s; + while ((r * 2 + 1) <= e) { + octa::RangeSize<_R> ch = r * 2 + 1; + octa::RangeSize<_R> 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 - MapRange<_R, octa::detail::MapReturnType<_R, _F>> map(_R __range, - _F __func) { - return octa::MapRange<_R, octa::detail::MapReturnType<_R, _F>>(__range, - __func); + template + void heapsort(_R range, _C compare) { + octa::RangeSize<_R> len = range.size(); + octa::RangeSize<_R> st = (len - 2) / 2; + for (;;) { + octa::detail::hs_sift_down(range, st, len - 1, compare); + if (st-- == 0) break; + } + octa::RangeSize<_R> e = len - 1; + while (e > 0) { + octa::swap(range[e], range[0]); + --e; + octa::detail::hs_sift_down(range, 0, e, compare); + } } - template - struct FilterRange: InputRange< - FilterRange<_T>, octa::CommonType, - octa::ForwardRangeTag>, - octa::RangeValue<_T>, octa::RangeReference<_T>, octa::RangeSize<_T> - > { - private: - _T __range; - octa::Function)> __pred; - - void advance_valid() { - while (!__range.empty() && !__pred(front())) __range.pop_front(); + template + void introloop(_R range, _C compare, RangeSize<_R> depth) { + if (range.size() <= 10) { + octa::detail::insort(range, compare); + return; } - - public: - FilterRange(): __range(), __pred() {} - - template - FilterRange(const _T &__range, const _P &__pred): __range(__range), - __pred(__pred) { - advance_valid(); - } - FilterRange(const FilterRange &__it): __range(__it.__range), - __pred(__it.__pred) { - advance_valid(); - } - FilterRange(FilterRange &&__it): __range(move(__it.__range)), - __pred(move(__it.__pred)) { - advance_valid(); + if (depth == 0) { + octa::detail::heapsort(range, compare); + return; } + octa::RangeReference<_R> p = range[range.size() / 2]; + octa::swap(p, range.back()); + _R r = octa::partition(range, + octa::detail::UnaryCompare{ p, compare }); + _R l = range.slice(0, range.size() - r.size()); + octa::swap(r.front(), r.back()); + octa::detail::introloop(l, compare, depth - 1); + octa::detail::introloop(r, compare, depth - 1); + } - FilterRange &operator=(const FilterRange &__v) { - __range = __v.__range; - __pred = __v.__pred; - advance_valid(); - return *this; - } - FilterRange &operator=(FilterRange &&__v) { - __range = move(__v.__range); - __pred = move(__v.__pred); - advance_valid(); - return *this; - } + template + void introsort(_R range, _C compare) { + octa::detail::introloop(range, compare, octa::RangeSize<_R>(2 + * (log(range.size()) / log(2)))); + } +} /* namespace detail */ - bool empty() const { return __range.empty(); } +template +void sort(_R range, _C compare) { + octa::detail::introsort(range, compare); +} - bool equals_front(const FilterRange &__r) const { - return __range.equals_front(__r.__range); - } +template +void sort(_R range) { + sort(range, octa::Less>()); +} - bool pop_front() { - bool __ret = __range.pop_front(); - advance_valid(); - return __ret; - } - bool push_front() { - _T __tmp = __range; - if (!__tmp.push_front()) return false; - while (!pred(__tmp.front())) - if (!__tmp.push_front()) - return false; - __range = __tmp; - return true; - } +/* min/max(_element) */ - octa::RangeReference<_T> front() const { return __range.front(); } - }; +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 - FilterRange<_R> filter(_R __range, _P __pred) { - return octa::FilterRange<_R>(__range, __pred); +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<_T> il) { + return octa::min_element(octa::each(il)).front(); +} +template +inline _T min(std::initializer_list<_T> il, _C compare) { + return octa::min_element(octa::each(il), compare).front(); +} + +template +inline _T max(std::initializer_list<_T> il) { + return octa::max_element(octa::each(il)).front(); +} + +template +inline _T max(std::initializer_list<_T> il, _C compare) { + return octa::max_element(octa::each(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<_R> count(_R range, const _T &v) { + RangeSize<_R> ret = 0; + for (; !range.empty(); range.pop_front()) + if (range.front() == v) + ++ret; + return ret; +} + +template +RangeSize<_R> count_if(_R range, _P pred) { + RangeSize<_R> ret = 0; + for (; !range.empty(); range.pop_front()) + if (pred(range.front())) + ++ret; + return ret; +} + +template +RangeSize<_R> count_if_not(_R range, _P pred) { + RangeSize<_R> 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<_R1, _R2> 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<_T, _R>, octa::RangeCategory<_T>, _R, _R, octa::RangeSize<_T> +> { +private: + _T p_range; + octa::Function<_R(octa::RangeReference<_T>)> p_func; + +public: + MapRange(): p_range(), p_func() {} + template + 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<_T> 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<_T> distance_front(const MapRange &r) const { + return p_range.distance_front(r.p_range); + } + octa::RangeDifference<_T> 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<_T> pop_front_n(octa::RangeSize<_T> n) { + p_range.pop_front_n(n); + } + octa::RangeSize<_T> pop_back_n(octa::RangeSize<_T> n) { + p_range.pop_back_n(n); + } + + octa::RangeSize<_T> push_front_n(octa::RangeSize<_T> n) { + return p_range.push_front_n(n); + } + octa::RangeSize<_T> push_back_n(octa::RangeSize<_T> 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<_T> idx) const { + return p_func(p_range[idx]); + } + + MapRange<_T, _R> slice(octa::RangeSize<_T> start, + octa::RangeSize<_T> end) { + return MapRange<_T, _R>(p_range.slice(start, end), p_func); + } +}; + +namespace detail { + template using MapReturnType + = decltype(declval<_F>()(octa::declval>())); +} + +template +MapRange<_R, octa::detail::MapReturnType<_R, _F>> map(_R range, + _F func) { + return octa::MapRange<_R, octa::detail::MapReturnType<_R, _F>>(range, + func); +} + +template +struct FilterRange: InputRange< + FilterRange<_T>, octa::CommonType, + octa::ForwardRangeTag>, + octa::RangeValue<_T>, octa::RangeReference<_T>, octa::RangeSize<_T> +> { +private: + _T p_range; + octa::Function)> p_pred; + + void advance_valid() { + while (!p_range.empty() && !p_pred(front())) p_range.pop_front(); + } + +public: + FilterRange(): p_range(), p_pred() {} + + 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; + } + bool push_front() { + _T tmp = p_range; + if (!tmp.push_front()) return false; + while (!p_pred(tmp.front())) + if (!tmp.push_front()) + return false; + p_range = tmp; + return true; + } + + octa::RangeReference<_T> front() const { return p_range.front(); } +}; + +template +FilterRange<_R> filter(_R range, _P pred) { + return octa::FilterRange<_R>(range, pred); +} + +} /* namespace octa */ + #endif \ No newline at end of file