#ifndef STAR_ALGORITHM_HPP #define STAR_ALGORITHM_HPP #include #include #include #include "StarException.hpp" namespace Star { // Function that does nothing and takes any number of arguments template void nothing(T&&...) {} // Functional constructor call / casting. template struct construct { template ToType operator()(FromTypes&&... fromTypes) const { return ToType(forward(fromTypes)...); } }; struct identity { template constexpr decltype(auto) operator()(U&& v) const { return std::forward(v); } }; template struct SwallowReturn { template void operator()(T&&... args) { func(forward(args)...); } Func func; }; template SwallowReturn swallow(Func f) { return SwallowReturn{move(f)}; } struct Empty { bool operator==(Empty const) const { return true; } bool operator<(Empty const) const { return false; } }; // Compose arbitrary functions template struct FunctionComposer { FirstFunction f1; SecondFunction f2; template decltype(auto) operator()(T&&... args) { return f1(f2(forward(args)...)); } }; template decltype(auto) compose(FirstFunction&& firstFunction, SecondFunction&& secondFunction) { return FunctionComposer{move(forward(firstFunction)), move(forward(secondFunction))}; } template decltype(auto) compose(FirstFunction firstFunction, SecondFunction secondFunction, ThirdFunction thirdFunction, RestFunctions... restFunctions) { return compose(forward(firstFunction), compose(forward(secondFunction), compose(forward(thirdFunction), forward(restFunctions)...))); } template Value fold(Container const& l, Value v, Function f) { auto i = l.begin(); auto e = l.end(); while (i != e) { v = f(v, *i); ++i; } return v; } // Like fold, but returns default value when container is empty. template typename Container::value_type fold1(Container const& l, Function f) { typename Container::value_type res = {}; typename Container::const_iterator i = l.begin(); typename Container::const_iterator e = l.end(); if (i == e) return res; res = *i; ++i; while (i != e) { res = f(res, *i); ++i; } return res; } // Return intersection of sorted containers. template Container intersect(Container const& a, Container const& b) { Container r; std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::inserter(r, r.end())); return r; } template bool mapMerge(MapType1& targetMap, MapType2 const& sourceMap, bool overwrite = false) { bool noCommonKeys = true; for (auto i = sourceMap.begin(); i != sourceMap.end(); ++i) { auto res = targetMap.insert(*i); if (!res.second) { noCommonKeys = false; if (overwrite) res.first->second = i->second; } } return noCommonKeys; } template bool mapsEqual(MapType1 const& m1, MapType2 const& m2) { if (&m1 == &m2) return true; if (m1.size() != m2.size()) return false; for (auto const& m1pair : m1) { auto m2it = m2.find(m1pair.first); if (m2it == m2.end() || !(m2it->second == m1pair.second)) return false; } return true; } template void filter(Container& container, Filter&& filter) { auto p = std::begin(container); while (p != std::end(container)) { if (!filter(*p)) p = container.erase(p); else ++p; } } template OutContainer filtered(InContainer const& input, Filter&& filter) { OutContainer out; auto p = std::begin(input); while (p != std::end(input)) { if (filter(*p)) out.insert(out.end(), *p); ++p; } return out; } template void eraseWhere(Container& container, Cond&& cond) { auto p = std::begin(container); while (p != std::end(container)) { if (cond(*p)) p = container.erase(p); else ++p; } } template void sort(Container& c, Compare comp) { std::sort(c.begin(), c.end(), comp); } template void stableSort(Container& c, Compare comp) { std::stable_sort(c.begin(), c.end(), comp); } template void sort(Container& c) { std::sort(c.begin(), c.end(), std::less()); } template void stableSort(Container& c) { std::stable_sort(c.begin(), c.end(), std::less()); } template Container sorted(Container const& c, Compare comp) { auto c2 = c; sort(c2, comp); return c2; } template Container stableSorted(Container const& c, Compare comp) { auto c2 = c; sort(c2, comp); return c2; } template Container sorted(Container const& c) { auto c2 = c; sort(c2); return c2; } template Container stableSorted(Container const& c) { auto c2 = c; sort(c2); return c2; } // Sort a container by the output of a computed value. The computed value is // only computed *once* per item in the container, which is useful both for // when the computed value is costly, and to avoid sorting instability with // floating point values. Container must have size() and operator[], and also // must be constructable with Container(size_t). template void sortByComputedValue(Container& container, Getter&& valueGetter, bool stable = false) { typedef typename Container::value_type ContainerValue; typedef decltype(valueGetter(ContainerValue())) ComputedValue; typedef std::pair ComputedPair; size_t containerSize = container.size(); if (containerSize <= 1) return; std::vector work(containerSize); for (size_t i = 0; i < containerSize; ++i) work[i] = {valueGetter(container[i]), i}; auto compare = [](ComputedPair const& a, ComputedPair const& b) { return a.first < b.first; }; // Sort the comptued values and the associated indexes if (stable) stableSort(work, compare); else sort(work, compare); Container result(containerSize); for (size_t i = 0; i < containerSize; ++i) swap(result[i], container[work[i].second]); swap(container, result); } template void stableSortByComputedValue(Container& container, Getter&& valueGetter) { return sortByComputedValue(container, forward(valueGetter), true); } template void shuffle(Container& c) { std::random_shuffle(c.begin(), c.end()); } template void reverse(Container& c) { std::reverse(c.begin(), c.end()); } template Container reverseCopy(Container c) { reverse(c); return c; } template T copy(T c) { return c; } template typename Container::value_type sum(Container const& cont) { return fold1(cont, std::plus()); } template typename Container::value_type product(Container const& cont) { return fold1(cont, std::multiplies()); } template void transformInto(OutContainer& outContainer, InContainer&& inContainer, Function&& function) { for (auto&& elem : inContainer) { if (std::is_rvalue_reference::value) outContainer.insert(outContainer.end(), function(move(elem))); else outContainer.insert(outContainer.end(), function(elem)); } } template OutContainer transform(InContainer&& container, Function&& function) { OutContainer res; transformInto(res, forward(container), forward(function)); return res; } template OutputContainer zipWith(Function&& function, Container1 const& cont1, Container2 const& cont2) { auto it1 = cont1.begin(); auto it2 = cont2.begin(); OutputContainer out; while (it1 != cont1.end() && it2 != cont2.end()) { out.insert(out.end(), function(*it1, *it2)); ++it1; ++it2; } return out; } // Moves the given value and into an rvalue. Works whether or not the type has // a valid move constructor or not. Always leaves the given value in its // default constructed state. template T take(T& t) { T t2 = move(t); t = T(); return t2; } template bool containersEqual(Container1 const& cont1, Container2 const& cont2) { if (cont1.size() != cont2.size()) return false; else return std::equal(cont1.begin(), cont1.end(), cont2.begin()); } // Wraps a unary function to produce an output iterator template class FunctionOutputIterator { public: typedef std::output_iterator_tag iterator_category; typedef void value_type; typedef void difference_type; typedef void pointer; typedef void reference; class OutputProxy { public: OutputProxy(UnaryFunction& f) : m_function(f) {} template OutputProxy& operator=(T&& value) { m_function(forward(value)); return *this; } private: UnaryFunction& m_function; }; explicit FunctionOutputIterator(UnaryFunction f = UnaryFunction()) : m_function(move(f)) {} OutputProxy operator*() { return OutputProxy(m_function); } FunctionOutputIterator& operator++() { return *this; } FunctionOutputIterator operator++(int) { return *this; } private: UnaryFunction m_function; }; template FunctionOutputIterator makeFunctionOutputIterator(UnaryFunction f) { return FunctionOutputIterator(move(f)); } // Wraps a nullary function to produce an input iterator template class FunctionInputIterator { public: typedef std::output_iterator_tag iterator_category; typedef void value_type; typedef void difference_type; typedef void pointer; typedef void reference; typedef typename std::result_of::type FunctionReturnType; explicit FunctionInputIterator(NullaryFunction f = {}) : m_function(move(f)) {} FunctionReturnType operator*() { return m_function(); } FunctionInputIterator& operator++() { return *this; } FunctionInputIterator operator++(int) { return *this; } private: NullaryFunction m_function; }; template FunctionInputIterator makeFunctionInputIterator(NullaryFunction f) { return FunctionInputIterator(move(f)); } template struct ReverseWrapper { private: Iterable& m_iterable; public: ReverseWrapper(Iterable& iterable) : m_iterable(iterable) {} decltype(auto) begin() const { return std::rbegin(m_iterable); } decltype(auto) end() const { return std::rend(m_iterable); } }; template ReverseWrapper reverseIterate(Iterable& list) { return ReverseWrapper(list); } template class FinallyGuard { public: FinallyGuard(Functor functor) : functor(move(functor)), dismiss(false) {} FinallyGuard(FinallyGuard&& o) : functor(move(o.functor)), dismiss(o.dismiss) { o.cancel(); } FinallyGuard& operator=(FinallyGuard&& o) { functor = move(o.functor); dismiss = o.dismiss; o.cancel(); return *this; } ~FinallyGuard() { if (!dismiss) functor(); } void cancel() { dismiss = true; } private: Functor functor; bool dismiss; }; template FinallyGuard::type> finally(Functor&& f) { return FinallyGuard(forward(f)); } // Generates compile time sequences of indexes from MinIndex to MaxIndex template struct IndexSequence {}; template struct GenIndexSequence : GenIndexSequence {}; template struct GenIndexSequence { typedef IndexSequence type; }; // Apply a tuple as individual arguments to a function template decltype(auto) tupleUnpackFunctionIndexes(Function&& function, Tuple&& args, IndexSequence const&) { return function(get(forward(args))...); } template decltype(auto) tupleUnpackFunction(Function&& function, Tuple&& args) { return tupleUnpackFunctionIndexes(forward(function), forward(args), typename GenIndexSequence<0, std::tuple_size::type>::value>::type()); } // Apply a function to every element of a tuple. This will NOT happen in a // predictable order! template decltype(auto) tupleApplyFunctionIndexes(Function&& function, Tuple&& args, IndexSequence const&) { return make_tuple(function(get(forward(args)))...); } template decltype(auto) tupleApplyFunction(Function&& function, Tuple&& args) { return tupleApplyFunctionIndexes(forward(function), forward(args), typename GenIndexSequence<0, std::tuple_size::type>::value>::type()); } // Use this version if you do not care about the return value of the function // or your function returns void. This version DOES happen in a predictable // order, first argument first, last argument last. template void tupleCallFunctionCaller(Function&&, Tuple&&) {} template void tupleCallFunctionCaller(Tuple&& t, Function&& function) { tupleCallFunctionCaller(forward(t), forward(function)); function(get(forward(t))); } template void tupleCallFunctionExpander(Tuple&& t, Function&& function, tuple const&) { tupleCallFunctionCaller(forward(t), forward(function)); } template void tupleCallFunction(Tuple&& t, Function&& function) { tupleCallFunctionExpander(forward(t), forward(function), forward(t)); } // Get a subset of a tuple template decltype(auto) subTupleIndexes(Tuple&& t, IndexSequence const&) { return make_tuple(get(forward(t))...); } template decltype(auto) subTuple(Tuple&& t) { return subTupleIndexes(forward(t), GenIndexSequence::type()); } template decltype(auto) trimTuple(Tuple&& t) { return subTupleIndexes(forward(t), typename GenIndexSequence::type>::value>::type()); } // Unpack a parameter expansion into a container template void unpackVariadicImpl(Container&) {} template void unpackVariadicImpl(Container& container, TFirst&& tfirst, TRest&&... trest) { container.insert(container.end(), forward(tfirst)); unpackVariadicImpl(container, forward(trest)...); } template Container unpackVariadic(T&&... t) { Container c; unpackVariadicImpl(c, forward(t)...); return c; } // Call a function on each entry in a variadic parameter set template void callFunctionVariadic(Function&&) {} template void callFunctionVariadic(Function&& function, Arg1&& arg1, ArgRest&&... argRest) { function(arg1); callFunctionVariadic(forward(function), forward(argRest)...); } template struct VariadicTypedef; template <> struct VariadicTypedef<> {}; template struct VariadicTypedef { typedef FirstT First; typedef VariadicTypedef Rest; }; // For generic types, directly use the result of the signature of its // 'operator()' template struct FunctionTraits : public FunctionTraits {}; template struct FunctionTraits { // arity is the number of arguments. static constexpr size_t Arity = sizeof...(ArgsTypes); typedef ReturnType Return; typedef VariadicTypedef Args; typedef tuple ArgTuple; template struct Arg { // the i-th argument is equivalent to the i-th tuple element of a tuple // composed of those arguments. typedef typename tuple_element::type type; }; }; template struct FunctionTraits : public FunctionTraits {}; template struct FunctionTraits> : public FunctionTraits {}; template struct FunctionTraits : public FunctionTraits { typedef ClassType& OwnerType; }; template struct FunctionTraits : public FunctionTraits { typedef const ClassType& OwnerType; }; template struct FunctionTraits : public FunctionTraits {}; template struct FunctionTraits : public FunctionTraits {}; template struct FunctionTraits : public FunctionTraits {}; template struct FunctionTraits : public FunctionTraits {}; } #endif