diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
commit | 6352e8e3196f78388b6c771073f9e03eaa612673 (patch) | |
tree | e23772f79a7fbc41bc9108951e9e136857484bf4 /source/core/StarAlgorithm.hpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/core/StarAlgorithm.hpp')
-rw-r--r-- | source/core/StarAlgorithm.hpp | 667 |
1 files changed, 667 insertions, 0 deletions
diff --git a/source/core/StarAlgorithm.hpp b/source/core/StarAlgorithm.hpp new file mode 100644 index 0000000..331f653 --- /dev/null +++ b/source/core/StarAlgorithm.hpp @@ -0,0 +1,667 @@ +#ifndef STAR_ALGORITHM_HPP +#define STAR_ALGORITHM_HPP + +#include <type_traits> +#include <vector> +#include <iterator> + +#include "StarException.hpp" + +namespace Star { + +// Function that does nothing and takes any number of arguments +template <typename... T> +void nothing(T&&...) {} + +// Functional constructor call / casting. +template <typename ToType> +struct construct { + template <typename... FromTypes> + ToType operator()(FromTypes&&... fromTypes) const { + return ToType(forward<FromTypes>(fromTypes)...); + } +}; + +struct identity { + template <typename U> + constexpr decltype(auto) operator()(U&& v) const { + return std::forward<U>(v); + } +}; + +template <typename Func> +struct SwallowReturn { + template <typename... T> + void operator()(T&&... args) { + func(forward<T>(args)...); + } + + Func func; +}; + +template <typename Func> +SwallowReturn<Func> swallow(Func f) { + return SwallowReturn<Func>{move(f)}; +} + +struct Empty { + bool operator==(Empty const) const { + return true; + } + + bool operator<(Empty const) const { + return false; + } +}; + +// Compose arbitrary functions +template <typename FirstFunction, typename SecondFunction> +struct FunctionComposer { + FirstFunction f1; + SecondFunction f2; + + template <typename... T> + decltype(auto) operator()(T&&... args) { + return f1(f2(forward<T>(args)...)); + } +}; + +template <typename FirstFunction, typename SecondFunction> +decltype(auto) compose(FirstFunction&& firstFunction, SecondFunction&& secondFunction) { + return FunctionComposer<FirstFunction, SecondFunction>{move(forward<FirstFunction>(firstFunction)), move(forward<SecondFunction>(secondFunction))}; +} + +template <typename FirstFunction, typename SecondFunction, typename ThirdFunction, typename... RestFunctions> +decltype(auto) compose(FirstFunction firstFunction, SecondFunction secondFunction, ThirdFunction thirdFunction, RestFunctions... restFunctions) { + return compose(forward<FirstFunction>(firstFunction), compose(forward<SecondFunction>(secondFunction), compose(forward<ThirdFunction>(thirdFunction), forward<RestFunctions>(restFunctions)...))); +} + +template <typename Container, typename Value, typename Function> +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, typename Function> +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 <typename Container> +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 <typename MapType1, typename MapType2> +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 <typename MapType1, typename MapType2> +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 <typename Container, typename Filter> +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 <typename OutContainer, typename InContainer, typename Filter> +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 <typename Container, typename Cond> +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 <typename Container, typename Compare> +void sort(Container& c, Compare comp) { + std::sort(c.begin(), c.end(), comp); +} + +template <typename Container, typename Compare> +void stableSort(Container& c, Compare comp) { + std::stable_sort(c.begin(), c.end(), comp); +} + +template <typename Container> +void sort(Container& c) { + std::sort(c.begin(), c.end(), std::less<typename Container::value_type>()); +} + +template <typename Container> +void stableSort(Container& c) { + std::stable_sort(c.begin(), c.end(), std::less<typename Container::value_type>()); +} + +template <typename Container, typename Compare> +Container sorted(Container const& c, Compare comp) { + auto c2 = c; + sort(c2, comp); + return c2; +} + +template <typename Container, typename Compare> +Container stableSorted(Container const& c, Compare comp) { + auto c2 = c; + sort(c2, comp); + return c2; +} + +template <typename Container> +Container sorted(Container const& c) { + auto c2 = c; + sort(c2); + return c2; +} + +template <typename Container> +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 <typename Container, typename Getter> +void sortByComputedValue(Container& container, Getter&& valueGetter, bool stable = false) { + typedef typename Container::value_type ContainerValue; + typedef decltype(valueGetter(ContainerValue())) ComputedValue; + typedef std::pair<ComputedValue, size_t> ComputedPair; + + size_t containerSize = container.size(); + + if (containerSize <= 1) + return; + + std::vector<ComputedPair> 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 <typename Container, typename Getter> +void stableSortByComputedValue(Container& container, Getter&& valueGetter) { + return sortByComputedValue(container, forward<Getter>(valueGetter), true); +} + +template <typename Container> +void shuffle(Container& c) { + std::random_shuffle(c.begin(), c.end()); +} + +template <typename Container> +void reverse(Container& c) { + std::reverse(c.begin(), c.end()); +} + +template <typename Container> +Container reverseCopy(Container c) { + reverse(c); + return c; +} + +template <typename T> +T copy(T c) { + return c; +} + +template <typename Container> +typename Container::value_type sum(Container const& cont) { + return fold1(cont, std::plus<typename Container::value_type>()); +} + +template <typename Container> +typename Container::value_type product(Container const& cont) { + return fold1(cont, std::multiplies<typename Container::value_type>()); +} + +template <typename OutContainer, typename InContainer, typename Function> +void transformInto(OutContainer& outContainer, InContainer&& inContainer, Function&& function) { + for (auto&& elem : inContainer) { + if (std::is_rvalue_reference<InContainer&&>::value) + outContainer.insert(outContainer.end(), function(move(elem))); + else + outContainer.insert(outContainer.end(), function(elem)); + } +} + +template <typename OutContainer, typename InContainer, typename Function> +OutContainer transform(InContainer&& container, Function&& function) { + OutContainer res; + transformInto(res, forward<InContainer>(container), forward<Function>(function)); + return res; +} + +template <typename OutputContainer, typename Function, typename Container1, typename Container2> +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 <typename T> +T take(T& t) { + T t2 = move(t); + t = T(); + return t2; +} + +template <typename Container1, typename Container2> +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 <typename UnaryFunction> +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 <typename T> + OutputProxy& operator=(T&& value) { + m_function(forward<T>(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 <typename UnaryFunction> +FunctionOutputIterator<UnaryFunction> makeFunctionOutputIterator(UnaryFunction f) { + return FunctionOutputIterator<UnaryFunction>(move(f)); +} + +// Wraps a nullary function to produce an input iterator +template <typename NullaryFunction> +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<NullaryFunction()>::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 <typename NullaryFunction> +FunctionInputIterator<NullaryFunction> makeFunctionInputIterator(NullaryFunction f) { + return FunctionInputIterator<NullaryFunction>(move(f)); +} + +template <typename Iterable> +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 <typename Iterable> +ReverseWrapper<Iterable> reverseIterate(Iterable& list) { + return ReverseWrapper<Iterable>(list); +} + +template <typename Functor> +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 <typename Functor> +FinallyGuard<typename std::decay<Functor>::type> finally(Functor&& f) { + return FinallyGuard<Functor>(forward<Functor>(f)); +} + +// Generates compile time sequences of indexes from MinIndex to MaxIndex + +template <size_t...> +struct IndexSequence {}; + +template <size_t Min, size_t N, size_t... S> +struct GenIndexSequence : GenIndexSequence<Min, N - 1, N - 1, S...> {}; + +template <size_t Min, size_t... S> +struct GenIndexSequence<Min, Min, S...> { + typedef IndexSequence<S...> type; +}; + +// Apply a tuple as individual arguments to a function + +template <typename Function, typename Tuple, size_t... Indexes> +decltype(auto) tupleUnpackFunctionIndexes(Function&& function, Tuple&& args, IndexSequence<Indexes...> const&) { + return function(get<Indexes>(forward<Tuple>(args))...); +} + +template <typename Function, typename Tuple> +decltype(auto) tupleUnpackFunction(Function&& function, Tuple&& args) { + return tupleUnpackFunctionIndexes<Function, Tuple>(forward<Function>(function), forward<Tuple>(args), + typename GenIndexSequence<0, std::tuple_size<typename std::decay<Tuple>::type>::value>::type()); +} + +// Apply a function to every element of a tuple. This will NOT happen in a +// predictable order! + +template <typename Function, typename Tuple, size_t... Indexes> +decltype(auto) tupleApplyFunctionIndexes(Function&& function, Tuple&& args, IndexSequence<Indexes...> const&) { + return make_tuple(function(get<Indexes>(forward<Tuple>(args)))...); +} + +template <typename Function, typename Tuple> +decltype(auto) tupleApplyFunction(Function&& function, Tuple&& args) { + return tupleApplyFunctionIndexes<Function, Tuple>(forward<Function>(function), forward<Tuple>(args), + typename GenIndexSequence<0, std::tuple_size<typename std::decay<Tuple>::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 <typename Function, typename Tuple> +void tupleCallFunctionCaller(Function&&, Tuple&&) {} + +template <typename Tuple, typename Function, typename First, typename... Rest> +void tupleCallFunctionCaller(Tuple&& t, Function&& function) { + tupleCallFunctionCaller<Tuple, Function, Rest...>(forward<Tuple>(t), forward<Function>(function)); + function(get<sizeof...(Rest)>(forward<Tuple>(t))); +} + +template <typename Tuple, typename Function, typename... T> +void tupleCallFunctionExpander(Tuple&& t, Function&& function, tuple<T...> const&) { + tupleCallFunctionCaller<Tuple, Function, T...>(forward<Tuple>(t), forward<Function>(function)); +} + +template <typename Tuple, typename Function> +void tupleCallFunction(Tuple&& t, Function&& function) { + tupleCallFunctionExpander<Tuple, Function>(forward<Tuple>(t), forward<Function>(function), forward<Tuple>(t)); +} + +// Get a subset of a tuple + +template <typename Tuple, size_t... Indexes> +decltype(auto) subTupleIndexes(Tuple&& t, IndexSequence<Indexes...> const&) { + return make_tuple(get<Indexes>(forward<Tuple>(t))...); +} + +template <size_t Min, size_t Size, typename Tuple> +decltype(auto) subTuple(Tuple&& t) { + return subTupleIndexes(forward<Tuple>(t), GenIndexSequence<Min, Size>::type()); +} + +template <size_t Trim, typename Tuple> +decltype(auto) trimTuple(Tuple&& t) { + return subTupleIndexes(forward<Tuple>(t), typename GenIndexSequence<Trim, std::tuple_size<typename std::decay<Tuple>::type>::value>::type()); +} + +// Unpack a parameter expansion into a container + +template <typename Container> +void unpackVariadicImpl(Container&) {} + +template <typename Container, typename TFirst, typename... TRest> +void unpackVariadicImpl(Container& container, TFirst&& tfirst, TRest&&... trest) { + container.insert(container.end(), forward<TFirst>(tfirst)); + unpackVariadicImpl(container, forward<TRest>(trest)...); +} + +template <typename Container, typename... T> +Container unpackVariadic(T&&... t) { + Container c; + unpackVariadicImpl(c, forward<T>(t)...); + return c; +} + +// Call a function on each entry in a variadic parameter set + +template <typename Function> +void callFunctionVariadic(Function&&) {} + +template <typename Function, typename Arg1, typename... ArgRest> +void callFunctionVariadic(Function&& function, Arg1&& arg1, ArgRest&&... argRest) { + function(arg1); + callFunctionVariadic(forward<Function>(function), forward<ArgRest>(argRest)...); +} + +template <typename... Rest> +struct VariadicTypedef; + +template <> +struct VariadicTypedef<> {}; + +template <typename FirstT, typename... RestT> +struct VariadicTypedef<FirstT, RestT...> { + typedef FirstT First; + typedef VariadicTypedef<RestT...> Rest; +}; + +// For generic types, directly use the result of the signature of its +// 'operator()' +template <typename T> +struct FunctionTraits : public FunctionTraits<decltype(&T::operator())> {}; + +template <typename ReturnType, typename... ArgsTypes> +struct FunctionTraits<ReturnType(ArgsTypes...)> { + // arity is the number of arguments. + static constexpr size_t Arity = sizeof...(ArgsTypes); + + typedef ReturnType Return; + + typedef VariadicTypedef<ArgsTypes...> Args; + typedef tuple<ArgsTypes...> ArgTuple; + + template <size_t i> + 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<i, ArgTuple>::type type; + }; +}; + +template <typename ReturnType, typename... Args> +struct FunctionTraits<ReturnType (*)(Args...)> : public FunctionTraits<ReturnType(Args...)> {}; + +template <typename FunctionType> +struct FunctionTraits<std::function<FunctionType>> : public FunctionTraits<FunctionType> {}; + +template <typename ClassType, typename ReturnType, typename... Args> +struct FunctionTraits<ReturnType (ClassType::*)(Args...)> : public FunctionTraits<ReturnType(Args...)> { + typedef ClassType& OwnerType; +}; + +template <typename ClassType, typename ReturnType, typename... Args> +struct FunctionTraits<ReturnType (ClassType::*)(Args...) const> : public FunctionTraits<ReturnType(Args...)> { + typedef const ClassType& OwnerType; +}; + +template <typename T> +struct FunctionTraits<T&> : public FunctionTraits<T> {}; + +template <typename T> +struct FunctionTraits<T const&> : public FunctionTraits<T> {}; + +template <typename T> +struct FunctionTraits<T&&> : public FunctionTraits<T> {}; + +template <typename T> +struct FunctionTraits<T const&&> : public FunctionTraits<T> {}; + +} + +#endif |