#pragma once #include #include #include #include #include #include #include #include #include #include namespace base { using StringIL = std::initializer_list; namespace impl { // When isField is true, following functors operate on a // pointers-to-field. Otherwise, they operate on a // pointers-to-const-method. template struct Less; template struct Less { Less(T C::* p) : m_p(p) {} bool operator()(C const & lhs, C const & rhs) const { return lhs.*m_p < rhs.*m_p; } bool operator()(C const * const lhs, C const * const rhs) const { return lhs->*m_p < rhs->*m_p; } T C::* m_p; }; template struct Less { Less(T (C::*p)() const) : m_p(p) {} bool operator()(C const & lhs, C const & rhs) const { return (lhs.*m_p)() < (rhs.*m_p)(); } bool operator()(C const * const lhs, C const * const rhs) const { return (lhs->*m_p)() < (rhs->*m_p)(); } T (C::*m_p)() const; }; template struct Equals; template struct Equals { Equals(T C::* p) : m_p(p) {} bool operator()(C const & lhs, C const & rhs) const { return lhs.*m_p == rhs.*m_p; } bool operator()(C const * const lhs, C const * const rhs) const { return lhs->*m_p == rhs->*m_p; } T C::* m_p; }; template struct Equals { Equals(T (C::*p)() const) : m_p(p) {} bool operator()(C const & lhs, C const & rhs) const { return (lhs.*m_p)() == (rhs.*m_p)(); } bool operator()(C const * const lhs, C const * const rhs) const { return (lhs->*m_p)() == (rhs->*m_p)(); } T (C::*m_p)() const; }; template class DeleteRangeFunctor { public: DeleteRangeFunctor(Container & cont, Deletor const & deletor) : m_cont(cont), m_deletor(deletor) { } void operator()() { for_each(m_cont.begin(), m_cont.end(), m_deletor); m_cont.clear(); } private: Container & m_cont; Deletor m_deletor; }; } // namespace impl // Sorts and removes duplicate entries from |c|. template void SortUnique(Cont & c) { sort(c.begin(), c.end()); c.erase(unique(c.begin(), c.end()), c.end()); } // Sorts according to |less| and removes duplicate entries according to |equals| from |c|. // Note. If several entries are equal according to |less| an arbitrary entry of them // is left in |c| after a call of this function. template void SortUnique(Cont & c, Less && less, Equals && equals) { sort(c.begin(), c.end(), std::forward(less)); c.erase(unique(c.begin(), c.end(), std::forward(equals)), c.end()); } template void EraseIf(Cont & c, Fn && fn) { c.erase(remove_if(c.begin(), c.end(), std::forward(fn)), c.end()); } // Creates a comparer being able to compare two instances of class C // (given by reference or pointer) by a field or const method of C. // For example, to create comparer that is able to compare pairs of // ints by second component, it's enough to call LessBy(&pair::second). template impl::Less LessBy(T C::* p) { return impl::Less(p); } template impl::Less LessBy(T (C::*p)() const) { return impl::Less(p); } template impl::Equals EqualsBy(T C::* p) { return impl::Equals(p); } template impl::Equals EqualsBy(T (C::*p)() const) { return impl::Equals(p); } template std::underlying_type_t constexpr Underlying(T value) { return static_cast>(value); } // Use this if you want to make a functor whose first // argument is ignored and the rest are forwarded to |fn|. template class IgnoreFirstArgument { public: template IgnoreFirstArgument(Gn && gn) : m_fn(std::forward(gn)) {} template std::result_of_t operator()(Arg && arg, Args &&... args) { return m_fn(std::forward(args)...); } private: Fn m_fn; }; template IgnoreFirstArgument MakeIgnoreFirstArgument(Fn && fn) { return IgnoreFirstArgument(std::forward(fn)); } template std::enable_if_t for_each_in_tuple(std::tuple &, Fn &&) { } template std::enable_if_t for_each_in_tuple(std::tuple & t, Fn && fn) { fn(I, std::get(t)); for_each_in_tuple(t, std::forward(fn)); } template std::enable_if_t for_each_in_tuple_const(std::tuple const &, Fn &&) { } template std::enable_if_t for_each_in_tuple_const(std::tuple const & t, Fn && fn) { fn(I, std::get(t)); for_each_in_tuple_const(t, std::forward(fn)); } template class BackInsertFunctor { public: explicit BackInsertFunctor(Container & container) : m_Container(container) {} void operator()(typename Container::value_type const & t) const { m_Container.push_back(t); } private: Container & m_Container; }; template BackInsertFunctor MakeBackInsertFunctor(Container & container) { return BackInsertFunctor(container); } template class InsertFunctor { public: explicit InsertFunctor(Container & container) : m_Container(container) {} void operator()(typename Container::value_type const & t) const { m_Container.insert(end(m_Container), t); } private: Container & m_Container; }; template InsertFunctor MakeInsertFunctor(Container & container) { return InsertFunctor(container); } template bool IsSortedAndUnique(Iter beg, Iter end, Compare comp) { if (beg == end) return true; Iter prev = beg; for (++beg; beg != end; ++beg, ++prev) { if (!comp(*prev, *beg)) return false; } return true; } template Iter RemoveIfKeepValid(Iter beg, Iter end, Compare comp) { while (beg != end) { if (comp(*beg)) { while (beg != --end) { if (!comp(*end)) { std::swap(*beg, *end); ++beg; break; } } } else ++beg; } return end; } template bool IsSortedAndUnique(Iter beg, Iter end) { return IsSortedAndUnique(beg, end, std::less::value_type>()); } struct DeleteFunctor { template void operator()(T const * p) const { delete p; } }; template impl::DeleteRangeFunctor GetRangeDeletor(Container & cont, Deletor const & deletor) { return impl::DeleteRangeFunctor(cont, deletor); } template void DeleteRange(Container & cont, Deletor const & deletor) { (void)GetRangeDeletor(cont, deletor)(); } struct IdFunctor { template T operator()(T const & x) const { return x; } }; template struct EqualFunctor { T const & m_t; explicit EqualFunctor(T const & t) : m_t(t) {} bool operator()(T const & t) const { return (t == m_t); } }; template Iter NextIterInCycle(Iter it, Iter beg, Iter end) { if (++it == end) return beg; return it; } template Iter PrevIterInCycle(Iter it, Iter beg, Iter end) { if (it == beg) it = end; return --it; } template void AccumulateIntervals1With2(Iter1 b1, Iter1 e1, Iter2 b2, Iter2 e2, InsertIter res) { using T = typename std::iterator_traits::value_type; T prev; bool validPrev = false; while (b1 != e1 || b2 != e2) { // Try to continue previous range. if (validPrev) { // add b1 range to prev if needed if (b1 != e1 && b1->first < prev.second) { // correct only second if needed if (prev.second < b1->second) prev.second = b1->second; ++b1; continue; } // add b2 range to prev if needed if (b2 != e2 && b2->first < prev.second) { // check that intervals are overlapped if (prev.first < b2->second) { // correct first and second if needed if (b2->first < prev.first) prev.first = b2->first; if (prev.second < b2->second) prev.second = b2->second; } ++b2; continue; } // if nothing to add - push to results *res++ = prev; validPrev = false; } if (b1 != e1) { // start new range prev = *b1++; validPrev = true; } else { // go to exit break; } } if (validPrev) *res++ = prev; } struct EnumClassHash { template::value> * = nullptr> size_t operator()(T const & t) const noexcept { return static_cast(t); } }; } // namespace base