From 6352e8e3196f78388b6c771073f9e03eaa612673 Mon Sep 17 00:00:00 2001 From: Kae <80987908+Novaenia@users.noreply.github.com> Date: Tue, 20 Jun 2023 14:33:09 +1000 Subject: everything everywhere all at once --- source/core/StarAlgorithm.hpp | 667 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 667 insertions(+) create mode 100644 source/core/StarAlgorithm.hpp (limited to 'source/core/StarAlgorithm.hpp') 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 +#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 -- cgit v1.2.3