#pragma once #include "is_in.h" #include "utility.h" #include #include #include #include #include #include namespace NPrivate { template constexpr I ExtremeElementBy(I begin, I end, F&& func, P&& pred) { if (begin == end) { return end; } auto bestValue = func(*begin); auto bestPos = begin; for (++begin; begin != end; ++begin) { auto curValue = func(*begin); if (pred(curValue, bestValue)) { bestValue = std::move(curValue); bestPos = begin; } } return bestPos; } } // namespace NPrivate template constexpr void Sort(T f, T l) { std::sort(f, l); } template constexpr void Sort(T f, T l, C c) { std::sort(f, l, c); } template constexpr void Sort(TContainer& container) { Sort(container.begin(), container.end()); } template constexpr void Sort(TContainer& container, TCompare compare) { Sort(container.begin(), container.end(), compare); } template constexpr void SortBy(TIterator begin, TIterator end, const TGetKey& getKey) { Sort(begin, end, [&](auto&& left, auto&& right) { return getKey(left) < getKey(right); }); } template constexpr void SortBy(TContainer& container, const TGetKey& getKey) { SortBy(container.begin(), container.end(), getKey); } template static inline void StableSort(T f, T l) { std::stable_sort(f, l); } template static inline void StableSort(T f, T l, C c) { std::stable_sort(f, l, c); } template static inline void StableSort(TContainer& container) { StableSort(container.begin(), container.end()); } template static inline void StableSort(TContainer& container, TCompare compare) { StableSort(container.begin(), container.end(), compare); } template static inline void StableSortBy(TIterator begin, TIterator end, const TGetKey& getKey) { StableSort(begin, end, [&](auto&& left, auto&& right) { return getKey(left) < getKey(right); }); } template static inline void StableSortBy(TContainer& container, const TGetKey& getKey) { StableSortBy(container.begin(), container.end(), getKey); } template constexpr void PartialSort(T f, T m, T l) { std::partial_sort(f, m, l); } template constexpr void PartialSort(T f, T m, T l, C c) { std::partial_sort(f, m, l, c); } template constexpr R PartialSortCopy(T f, T l, R of, R ol) { return std::partial_sort_copy(f, l, of, ol); } template constexpr R PartialSortCopy(T f, T l, R of, R ol, C c) { return std::partial_sort_copy(f, l, of, ol, c); } template constexpr I Find(I f, I l, const T& v) { return std::find(f, l, v); } template constexpr auto Find(C&& c, const T& v) { using std::begin; using std::end; return std::find(begin(c), end(c), v); } // FindPtr - return NULL if not found. Works for arrays, containers, iterators template constexpr auto FindPtr(I f, I l, const T& v) -> decltype(&*f) { I found = Find(f, l, v); return (found != l) ? &*found : nullptr; } template constexpr auto FindPtr(C&& c, const T& v) { using std::begin; using std::end; return FindPtr(begin(c), end(c), v); } template constexpr I FindIf(I f, I l, P p) { return std::find_if(f, l, p); } template constexpr auto FindIf(C&& c, P p) { using std::begin; using std::end; return FindIf(begin(c), end(c), p); } template constexpr bool AllOf(I f, I l, P pred) { return std::all_of(f, l, pred); } template constexpr bool AllOf(const C& c, P pred) { using std::begin; using std::end; return AllOf(begin(c), end(c), pred); } template constexpr bool AnyOf(I f, I l, P pred) { return std::any_of(f, l, pred); } template constexpr bool AnyOf(const C& c, P pred) { using std::begin; using std::end; return AnyOf(begin(c), end(c), pred); } // FindIfPtr - return NULL if not found. Works for arrays, containers, iterators template constexpr auto FindIfPtr(I f, I l, P pred) -> decltype(&*f) { I found = FindIf(f, l, pred); return (found != l) ? &*found : nullptr; } template constexpr auto FindIfPtr(C&& c, P pred) { using std::begin; using std::end; return FindIfPtr(begin(c), end(c), pred); } template constexpr size_t FindIndex(C&& c, const T& x) { using std::begin; using std::end; auto it = Find(begin(c), end(c), x); return it == end(c) ? NPOS : (it - begin(c)); } template constexpr size_t FindIndexIf(C&& c, P p) { using std::begin; using std::end; auto it = FindIf(begin(c), end(c), p); return it == end(c) ? NPOS : (it - begin(c)); } // EqualToOneOf(x, "apple", "orange") means (x == "apple" || x == "orange") template constexpr bool EqualToOneOf(const T& x, const Other&... values) { return (... || (x == values)); } template constexpr size_t CountOf(const T& x, const Other&... values) { return (0 + ... + static_cast(x == values)); } template constexpr void PushHeap(I f, I l) { std::push_heap(f, l); } template constexpr void PushHeap(I f, I l, C c) { std::push_heap(f, l, c); } template constexpr void PopHeap(I f, I l) { std::pop_heap(f, l); } template constexpr void PopHeap(I f, I l, C c) { std::pop_heap(f, l, c); } template constexpr void MakeHeap(I f, I l) { std::make_heap(f, l); } template constexpr void MakeHeap(I f, I l, C c) { std::make_heap(f, l, c); } template constexpr void SortHeap(I f, I l) { std::sort_heap(f, l); } template constexpr void SortHeap(I f, I l, C c) { std::sort_heap(f, l, c); } template constexpr I LowerBound(I f, I l, const T& v) { return std::lower_bound(f, l, v); } template constexpr I LowerBound(I f, I l, const T& v, C c) { return std::lower_bound(f, l, v, c); } template constexpr I LowerBoundBy(I f, I l, const T& v, const TGetKey& getKey) { return std::lower_bound(f, l, v, [&](auto&& left, auto&& right) { return getKey(left) < right; }); } template constexpr I UpperBound(I f, I l, const T& v) { return std::upper_bound(f, l, v); } template constexpr I UpperBound(I f, I l, const T& v, C c) { return std::upper_bound(f, l, v, c); } template constexpr I UpperBoundBy(I f, I l, const T& v, const TGetKey& getKey) { return std::upper_bound(f, l, v, [&](auto&& left, auto&& right) { return left < getKey(right); }); } template constexpr T Unique(T f, T l) { return std::unique(f, l); } template constexpr T Unique(T f, T l, P p) { return std::unique(f, l, p); } template constexpr T UniqueBy(T f, T l, const TGetKey& getKey) { return Unique(f, l, [&](auto&& left, auto&& right) { return getKey(left) == getKey(right); }); } template void SortUnique(C& c) { Sort(c.begin(), c.end()); c.erase(Unique(c.begin(), c.end()), c.end()); } template void SortUnique(C& c, Cmp cmp) { Sort(c.begin(), c.end(), cmp); c.erase(Unique(c.begin(), c.end()), c.end()); } template void SortUniqueBy(C& c, const TGetKey& getKey) { SortBy(c, getKey); c.erase(UniqueBy(c.begin(), c.end(), getKey), c.end()); } template void StableSortUniqueBy(C& c, const TGetKey& getKey) { StableSortBy(c, getKey); c.erase(UniqueBy(c.begin(), c.end(), getKey), c.end()); } template void Erase(C& c, const TValue& value) { c.erase(std::remove(c.begin(), c.end(), value), c.end()); } template void EraseIf(C& c, P p) { c.erase(std::remove_if(c.begin(), c.end(), p), c.end()); } template void EraseNodesIf(C& c, P p) { for (auto iter = c.begin(), last = c.end(); iter != last;) { if (p(*iter)) { c.erase(iter++); } else { ++iter; } } } template constexpr bool Equal(T1 f1, T1 l1, T2 f2) { return std::equal(f1, l1, f2); } template constexpr bool Equal(T1 f1, T1 l1, T2 f2, P p) { return std::equal(f1, l1, f2, p); } template constexpr TO Copy(TI f, TI l, TO t) { return std::copy(f, l, t); } template constexpr TO UniqueCopy(TI f, TI l, TO t) { return std::unique_copy(f, l, t); } template constexpr TO UniqueCopy(TI f, TI l, TO t, TP p) { return std::unique_copy(f, l, t, p); } template constexpr TO RemoveCopyIf(TI f, TI l, TO t, TP p) { return std::remove_copy_if(f, l, t, p); } template constexpr TO ReverseCopy(TI f, TI l, TO t) { return std::reverse_copy(f, l, t); } template constexpr TO SetUnion(TI1 f1, TI1 l1, TI2 f2, TI2 l2, TO p) { return std::set_union(f1, l1, f2, l2, p); } template constexpr TO SetUnion(TI1 f1, TI1 l1, TI2 f2, TI2 l2, TO p, TC c) { return std::set_union(f1, l1, f2, l2, p, c); } template constexpr TO SetDifference(TI1 f1, TI1 l1, TI2 f2, TI2 l2, TO p) { return std::set_difference(f1, l1, f2, l2, p); } template constexpr TO SetDifference(TI1 f1, TI1 l1, TI2 f2, TI2 l2, TO p, TC c) { return std::set_difference(f1, l1, f2, l2, p, c); } template constexpr TO SetSymmetricDifference(TI1 f1, TI1 l1, TI2 f2, TI2 l2, TO p) { return std::set_symmetric_difference(f1, l1, f2, l2, p); } template constexpr TO SetSymmetricDifference(TI1 f1, TI1 l1, TI2 f2, TI2 l2, TO p, TC c) { return std::set_symmetric_difference(f1, l1, f2, l2, p, c); } template constexpr TO SetIntersection(TI1 f1, TI1 l1, TI2 f2, TI2 l2, TO p) { return std::set_intersection(f1, l1, f2, l2, p); } template constexpr TO SetIntersection(TI1 f1, TI1 l1, TI2 f2, TI2 l2, TO p, TC c) { return std::set_intersection(f1, l1, f2, l2, p, c); } template constexpr void Fill(I f, I l, const T& v) { std::fill(f, l, v); } template constexpr I FillN(I f, S n, const T& v) { return std::fill_n(f, n, v); } template constexpr void Reverse(T f, T l) { std::reverse(f, l); } template constexpr void Rotate(T f, T m, T l) { std::rotate(f, m, l); } template constexpr Val Accumulate(It begin, It end, Val val) { // std::move since C++20 return std::accumulate(begin, end, std::move(val)); } template constexpr Val Accumulate(It begin, It end, Val val, BinOp binOp) { // std::move since C++20 return std::accumulate(begin, end, std::move(val), binOp); } template constexpr Val Accumulate(const C& c, Val val) { // std::move since C++20 return Accumulate(std::begin(c), std::end(c), std::move(val)); } template constexpr Val Accumulate(const C& c, Val val, BinOp binOp) { // std::move since C++20 return Accumulate(std::begin(c), std::end(c), std::move(val), binOp); } template constexpr Val InnerProduct(It1 begin1, It1 end1, It2 begin2, Val val) { return std::inner_product(begin1, end1, begin2, val); } template constexpr Val InnerProduct(It1 begin1, It1 end1, It2 begin2, Val val, BinOp1 binOp1, BinOp2 binOp2) { return std::inner_product(begin1, end1, begin2, val, binOp1, binOp2); } template constexpr typename TVectorType::value_type InnerProduct(const TVectorType& lhs, const TVectorType& rhs, typename TVectorType::value_type val = typename TVectorType::value_type()) { return std::inner_product(lhs.begin(), lhs.end(), rhs.begin(), val); } template constexpr typename TVectorType::value_type InnerProduct(const TVectorType& lhs, const TVectorType& rhs, typename TVectorType::value_type val, BinOp1 binOp1, BinOp2 binOp2) { return std::inner_product(lhs.begin(), lhs.end(), rhs.begin(), val, binOp1, binOp2); } template constexpr T MinElement(T begin, T end) { return std::min_element(begin, end); } template constexpr T MinElement(T begin, T end, C comp) { return std::min_element(begin, end, comp); } template constexpr T MaxElement(T begin, T end) { return std::max_element(begin, end); } template constexpr T MaxElement(T begin, T end, C comp) { return std::max_element(begin, end, comp); } template constexpr I MaxElementBy(I begin, I end, F&& func) { using TValue = decltype(func(*begin)); return ::NPrivate::ExtremeElementBy(begin, end, std::forward(func), TGreater()); } template constexpr auto MaxElementBy(C& c, F&& func) { return MaxElementBy(std::begin(c), std::end(c), std::forward(func)); } template constexpr auto MaxElementBy(const C& c, F&& func) { return MaxElementBy(std::begin(c), std::end(c), std::forward(func)); } template constexpr I MinElementBy(I begin, I end, F&& func) { using TValue = decltype(func(*begin)); return ::NPrivate::ExtremeElementBy(begin, end, std::forward(func), TLess()); } template constexpr auto MinElementBy(C& c, F&& func) { return MinElementBy(std::begin(c), std::end(c), std::forward(func)); } template constexpr auto MinElementBy(const C& c, F&& func) { return MinElementBy(std::begin(c), std::end(c), std::forward(func)); } template void ApplyToMany(TOp op, TArgs&&... args) { int dummy[] = {((void)op(std::forward(args)), 0)...}; Y_UNUSED(dummy); } template constexpr void ForEach(TI f, TI l, TOp op) { std::for_each(f, l, op); } namespace NPrivate { template constexpr bool AllOfImpl(T&& t, TOp&& op, std::index_sequence) { #if _LIBCPP_STD_VER >= 17 return (true && ... && op(std::get(std::forward(t)))); #else bool result = true; auto wrapper = [&result, &op](auto&& x) { result = result && op(std::forward(x)); }; int dummy[] = {(wrapper(std::get(std::forward(t))), 0)...}; Y_UNUSED(dummy); return result; #endif } template constexpr bool AnyOfImpl(T&& t, TOp&& op, std::index_sequence) { #if _LIBCPP_STD_VER >= 17 return (false || ... || op(std::get(std::forward(t)))); #else bool result = false; auto wrapper = [&result, &op](auto&& x) { result = result || op(std::forward(x)); }; int dummy[] = {(wrapper(std::get(std::forward(t))), 0)...}; Y_UNUSED(dummy); return result; #endif } template constexpr void ForEachImpl(T&& t, TOp&& op, std::index_sequence) { #if _LIBCPP_STD_VER >= 17 (..., op(std::get(std::forward(t)))); #else ::ApplyToMany(std::forward(op), std::get(std::forward(t))...); #endif } } // namespace NPrivate // check that TOp return true for all of element from tuple T template constexpr ::TEnableIfTuple AllOf(T&& t, TOp&& op) { return ::NPrivate::AllOfImpl( std::forward(t), std::forward(op), std::make_index_sequence>::value>{}); } // check that TOp return true for at least one element from tuple T template constexpr ::TEnableIfTuple AnyOf(T&& t, TOp&& op) { return ::NPrivate::AnyOfImpl( std::forward(t), std::forward(op), std::make_index_sequence>::value>{}); } template constexpr ::TEnableIfTuple ForEach(T&& t, TOp&& op) { ::NPrivate::ForEachImpl( std::forward(t), std::forward(op), std::make_index_sequence>::value>{}); } template constexpr void Transform(T1 b, T1 e, T2 o, O f) { std::transform(b, e, o, f); } template constexpr void Transform(T1 b1, T1 e1, T2 b2, T3 o, O f) { std::transform(b1, e1, b2, o, f); } template constexpr typename std::iterator_traits::difference_type Count(T first, T last, const V& value) { return std::count(first, last, value); } template constexpr auto Count(const TContainer& container, const TValue& value) { return Count(std::cbegin(container), std::cend(container), value); } template constexpr auto CountIf(It first, It last, P p) { return std::count_if(first, last, p); } template constexpr auto CountIf(const C& c, P pred) { using std::begin; using std::end; return CountIf(begin(c), end(c), pred); } template constexpr std::pair Mismatch(I1 b1, I1 e1, I2 b2) { return std::mismatch(b1, e1, b2); } template constexpr std::pair Mismatch(I1 b1, I1 e1, I2 b2, P p) { return std::mismatch(b1, e1, b2, p); } template constexpr void NthElement(RandomIterator begin, RandomIterator nth, RandomIterator end) { std::nth_element(begin, nth, end); } template constexpr void NthElement(RandomIterator begin, RandomIterator nth, RandomIterator end, Compare compare) { std::nth_element(begin, nth, end, compare); } // no standard implementation until C++14 template constexpr std::pair Mismatch(I1 b1, I1 e1, I2 b2, I2 e2) { while (b1 != e1 && b2 != e2 && *b1 == *b2) { ++b1; ++b2; } return std::make_pair(b1, b2); } template constexpr std::pair Mismatch(I1 b1, I1 e1, I2 b2, I2 e2, P p) { while (b1 != e1 && b2 != e2 && p(*b1, *b2)) { ++b1; ++b2; } return std::make_pair(b1, b2); } template constexpr bool BinarySearch(It begin, It end, const Val& val) { return std::binary_search(begin, end, val); } template constexpr bool BinarySearch(It begin, It end, const Val& val, Comp comp) { return std::binary_search(begin, end, val, comp); } template constexpr std::pair EqualRange(It begin, It end, const Val& val) { return std::equal_range(begin, end, val); } template constexpr std::pair EqualRange(It begin, It end, const Val& val, Comp comp) { return std::equal_range(begin, end, val, comp); } template constexpr auto AdjacentFind(TContainer&& c) { using std::begin; using std::end; return std::adjacent_find(begin(c), end(c)); } template constexpr auto AdjacentFind(TContainer&& c, Compare comp) { using std::begin; using std::end; return std::adjacent_find(begin(c), end(c), comp); } namespace NPrivate { template constexpr TForwardIterator AdjacentFindBy(TForwardIterator begin, TForwardIterator end, const TGetKey& getKey) { return std::adjacent_find(begin, end, [&](auto&& left, auto&& right) { return getKey(left) == getKey(right); }); } } // namespace NPrivate template constexpr auto AdjacentFindBy(TContainer&& c, const TGetKey& getKey) { using std::begin; using std::end; return ::NPrivate::AdjacentFindBy(begin(c), end(c), getKey); } template constexpr bool IsSorted(ForwardIt begin, ForwardIt end) { return std::is_sorted(begin, end); } template constexpr bool IsSorted(ForwardIt begin, ForwardIt end, Compare comp) { return std::is_sorted(begin, end, comp); } template constexpr bool IsSortedBy(TIterator begin, TIterator end, const TGetKey& getKey) { return IsSorted(begin, end, [&](auto&& left, auto&& right) { return getKey(left) < getKey(right); }); } template constexpr bool IsSortedBy(const TContainer& c, const TGetKey& getKey) { using std::begin; using std::end; return IsSortedBy(begin(c), end(c), getKey); } template constexpr void Iota(It begin, It end, Val val) { std::iota(begin, end, val); } template constexpr TO CopyN(TI from, S s, TO to) { return std::copy_n(from, s, to); } template constexpr TO CopyIf(TI begin, TI end, TO to, P pred) { return std::copy_if(begin, end, to, pred); } template constexpr std::pair MinMax(const T& first Y_LIFETIME_BOUND, const T& second Y_LIFETIME_BOUND) { return std::minmax(first, second); } template constexpr std::pair MinMaxElement(It first, It last) { return std::minmax_element(first, last); } template constexpr void Generate(TIterator first, TIterator last, TGenerator generator) { std::generate(first, last, generator); } template constexpr void GenerateN(TIterator first, TSize count, TGenerator generator) { std::generate_n(first, count, generator); }