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/StarPythonic.hpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/core/StarPythonic.hpp')
-rw-r--r-- | source/core/StarPythonic.hpp | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/source/core/StarPythonic.hpp b/source/core/StarPythonic.hpp new file mode 100644 index 0000000..014e14e --- /dev/null +++ b/source/core/StarPythonic.hpp @@ -0,0 +1,603 @@ +#ifndef STAR_PYTHONIC_HPP +#define STAR_PYTHONIC_HPP + +#include "StarAlgorithm.hpp" + +namespace Star { + +// any and all + +template <typename Iterator, typename Functor> +bool any(Iterator iterBegin, Iterator iterEnd, Functor const& f) { + for (; iterBegin != iterEnd; iterBegin++) + if (f(*iterBegin)) + return true; + return false; +} + +template <typename Iterator> +bool any(Iterator const& iterBegin, Iterator const& iterEnd) { + typedef typename std::iterator_traits<Iterator>::value_type IteratorValue; + std::function<bool(IteratorValue)> compare = [](IteratorValue const& i) { return (bool)i; }; + return any(iterBegin, iterEnd, compare); +} + +template <typename Iterable, typename Functor> +bool any(Iterable const& iter, Functor const& f) { + return any(std::begin(iter), std::end(iter), f); +} + +template <typename Iterable> +bool any(Iterable const& iter) { + typedef decltype(*std::begin(iter)) IteratorValue; + std::function<bool(IteratorValue)> compare = [](IteratorValue const& i) { return (bool)i; }; + return any(std::begin(iter), std::end(iter), compare); +} + +template <typename Iterator, typename Functor> +bool all(Iterator iterBegin, Iterator iterEnd, Functor const& f) { + for (; iterBegin != iterEnd; iterBegin++) + if (!f(*iterBegin)) + return false; + return true; +} + +template <typename Iterator> +bool all(Iterator const& iterBegin, Iterator const& iterEnd) { + typedef typename std::iterator_traits<Iterator>::value_type IteratorValue; + std::function<bool(IteratorValue)> compare = [](IteratorValue const& i) { return (bool)i; }; + return all(iterBegin, iterEnd, compare); +} + +template <typename Iterable, typename Functor> +bool all(Iterable const& iter, Functor const& f) { + return all(std::begin(iter), std::end(iter), f); +} + +template <typename Iterable> +bool all(Iterable const& iter) { + typedef decltype(*std::begin(iter)) IteratorValue; + std::function<bool(IteratorValue)> compare = [](IteratorValue const& i) { return (bool)i; }; + return all(std::begin(iter), std::end(iter), compare); +} + +// Python style container slicing + +struct SliceIndex { + SliceIndex() : index(0), given(false) {} + SliceIndex(int i) : index(i), given(true) {} + + int index; + bool given; +}; + +SliceIndex const SliceNil = SliceIndex(); + +// T must have operator[](int), size(), and +// push_back(typeof T::operator[](int())) +template <typename Res, typename In> +Res slice(In const& r, SliceIndex a, SliceIndex b = SliceIndex(), int j = 1) { + int size = (int)r.size(); + int start, end; + + // Throw exception on j == 0? + if (j == 0 || size == 0) + return Res(); + + if (!a.given) { + if (j > 0) + start = 0; + else + start = size - 1; + } else if (a.index < 0) { + if (-a.index > size - 1) + start = 0; + else + start = size - -a.index; + } else { + if (a.index > size) + start = size; + else + start = a.index; + } + + if (!b.given) { + if (j > 0) + end = size; + else + end = -1; + } else if (b.index < 0) { + if (-b.index > size - 1) { + end = -1; + } else { + end = size - -b.index; + } + } else { + if (b.index > size - 1) { + end = size; + } else { + end = b.index; + } + } + + if (start < end && j < 0) + return Res(); + if (start > end && j > 0) + return Res(); + + Res returnSlice; + int i; + for (i = start; i < end; i += j) + returnSlice.push_back(r[i]); + + return returnSlice; +} + +template <typename T> +T slice(T const& r, SliceIndex a, SliceIndex b = SliceIndex(), int j = 1) { + return slice<T, T>(r, a, b, j); +} + +// ZIP + +// Wraps a regular iterator and returns a singleton tuple, as well as +// supporting the iterator protocol that the zip iterator code expects. +template <typename IteratorT> +class ZipWrapperIterator { +private: + IteratorT current; + IteratorT last; + bool atEnd; + +public: + typedef IteratorT Iterator; + typedef decltype(*std::declval<Iterator>()) IteratorValue; + typedef tuple<IteratorValue> value_type; + + ZipWrapperIterator() : atEnd(true) {} + + ZipWrapperIterator(Iterator current, Iterator last) : current(current), last(last) { + atEnd = current == last; + } + + ZipWrapperIterator operator++() { + if (!atEnd) { + ++current; + atEnd = current == last; + } + + return *this; + } + + value_type operator*() const { + return std::tuple<IteratorValue>(*current); + } + + bool operator==(ZipWrapperIterator const& rhs) const { + return (atEnd && rhs.atEnd) || (!atEnd && !rhs.atEnd && current == rhs.current && last == rhs.last); + } + + bool operator!=(ZipWrapperIterator const& rhs) const { + return !(*this == rhs); + } + + explicit operator bool() const { + return !atEnd; + } + + ZipWrapperIterator begin() const { + return *this; + } + + ZipWrapperIterator end() const { + return ZipWrapperIterator(); + } +}; +template <typename IteratorT> +ZipWrapperIterator<IteratorT> makeZipWrapperIterator(IteratorT current, IteratorT end) { + return ZipWrapperIterator<IteratorT>(current, end); +} + +// Takes two ZipIterators / ZipTupleIterators and concatenates them into a +// single iterator that returns the concatenated tuple. +template <typename TailIteratorT, typename HeadIteratorT> +class ZipTupleIterator { +private: + TailIteratorT tailIterator; + HeadIteratorT headIterator; + bool atEnd; + +public: + typedef TailIteratorT TailIterator; + typedef HeadIteratorT HeadIterator; + + typedef decltype(*TailIterator()) TailType; + typedef decltype(*HeadIterator()) HeadType; + + typedef decltype(std::tuple_cat(std::declval<TailType>(), std::declval<HeadType>())) value_type; + + ZipTupleIterator() : atEnd(true) {} + + ZipTupleIterator(TailIterator tailIterator, HeadIterator headIterator) + : tailIterator(tailIterator), headIterator(headIterator) { + atEnd = tailIterator == TailIterator() || headIterator == HeadIterator(); + } + + ZipTupleIterator operator++() { + if (!atEnd) { + ++tailIterator; + ++headIterator; + atEnd = tailIterator == TailIterator() || headIterator == HeadIterator(); + } + + return *this; + } + + value_type operator*() const { + return std::tuple_cat(*tailIterator, *headIterator); + } + + bool operator==(ZipTupleIterator const& rhs) const { + return (atEnd && rhs.atEnd) + || (!atEnd && !rhs.atEnd && tailIterator == rhs.tailIterator && headIterator == rhs.headIterator); + } + + bool operator!=(ZipTupleIterator const& rhs) const { + return !(*this == rhs); + } + + explicit operator bool() const { + return !atEnd; + } + + ZipTupleIterator begin() const { + return *this; + } + + ZipTupleIterator end() const { + return ZipTupleIterator(); + } +}; +template <typename HeadIteratorT, typename TailIteratorT> +ZipTupleIterator<HeadIteratorT, TailIteratorT> makeZipTupleIterator(HeadIteratorT head, TailIteratorT tail) { + return ZipTupleIterator<HeadIteratorT, TailIteratorT>(head, tail); +} + +template <typename Container, typename... Rest> +struct zipIteratorReturn { + typedef ZipTupleIterator<typename zipIteratorReturn<Container>::type, typename zipIteratorReturn<Rest...>::type> type; +}; + +template <typename Container> +struct zipIteratorReturn<Container> { + typedef ZipWrapperIterator<decltype(std::declval<Container>().begin())> type; +}; + +template <typename Container> +typename zipIteratorReturn<Container>::type zipIterator(Container& container) { + return makeZipWrapperIterator(container.begin(), container.end()); +} + +template <typename Container, typename... Rest> +typename zipIteratorReturn<Container, Rest...>::type zipIterator(Container& container, Rest&... rest) { + return makeZipTupleIterator(makeZipWrapperIterator(container.begin(), container.end()), zipIterator(rest...)); +} + +// END ZIP + +// RANGE + +namespace RangeHelper { + + template <typename Diff> + typename std::enable_if<std::is_unsigned<Diff>::value, bool>::type checkIfDiffLessThanZero(Diff) { + return false; + } + + template <typename Diff> + typename std::enable_if<!std::is_unsigned<Diff>::value, bool>::type checkIfDiffLessThanZero(Diff diff) { + return diff < 0; + } +} + +STAR_EXCEPTION(RangeException, StarException); + +template <typename Value, typename Diff = int> +class RangeIterator : public std::iterator<std::random_access_iterator_tag, Value> { +public: + RangeIterator() : m_start(), m_end(), m_diff(1), m_current(), m_stop(true) {} + + RangeIterator(Value min, Value max, Diff diff) + : m_start(min), m_end(max), m_diff(diff), m_current(min), m_stop(false) { + sanity(); + } + + RangeIterator(Value min, Value max) : m_start(min), m_end(max), m_diff(1), m_current(min), m_stop(false) { + sanity(); + } + + RangeIterator(Value max) : m_start(), m_end(max), m_diff(1), m_current(), m_stop(false) { + sanity(); + } + + RangeIterator(RangeIterator const& rhs) { + copy(rhs); + } + + RangeIterator& operator=(RangeIterator const& rhs) { + copy(rhs); + return *this; + } + + RangeIterator& operator+=(Diff steps) { + if ((applySteps(m_current, m_diff * steps) >= m_end) != (RangeHelper::checkIfDiffLessThanZero<Diff>(m_diff))) { + if (!m_stop) { + Diff stepsLeft = stepsBetween(m_current, m_end); + m_current = applySteps(m_current, stepsLeft * m_diff); + m_stop = true; + } + } else { + m_current = applySteps(m_current, steps * m_diff); + } + return *this; + } + + RangeIterator operator-=(Diff steps) const { + m_stop = false; + sanity(); + + if (applySteps(m_current, -(m_diff * steps)) < m_start) + m_current = m_start; + else + m_current = applySteps(m_current, -(m_diff * steps)); + + return *this; + } + + Value operator*() const { + return m_current; + } + + Value const* operator->() const { + return &m_current; + } + + Value operator[](unsigned rhs) const { + // Should return at maximum, the value that this iterator will normally + // reach when at end(). + rhs = std::min(rhs, stepsBetween(m_start, m_end) + 1); + return m_start + rhs * m_diff; + } + + RangeIterator& operator++() { + return operator+=(1); + } + + RangeIterator& operator--() { + return operator-=(1); + } + + RangeIterator operator++(int) { + RangeIterator tmp(*this); + ++this; + return tmp; + } + + RangeIterator operator--(int) { + RangeIterator tmp(*this); + --this; + return tmp; + } + + RangeIterator operator+(Diff steps) const { + RangeIterator copy(*this); + copy += steps; + return copy; + } + + RangeIterator operator-(Diff steps) const { + RangeIterator copy(*this); + copy -= steps; + return copy; + } + + int operator-(RangeIterator const& rhs) const { + if (!sameClass(rhs)) + throw RangeException("Attempted to subtract incompatible ranges."); + + return stepsBetween(rhs.m_current, m_current); + } + + friend RangeIterator operator+(Diff lhs, RangeIterator const& rhs) { + return rhs + lhs; + } + + friend RangeIterator operator-(Diff lhs, RangeIterator const& rhs) { + return rhs - lhs; + } + + bool operator==(RangeIterator const& rhs) const { + return (sameClass(rhs) && m_current == rhs.m_current && m_stop == rhs.m_stop); + } + + bool operator!=(RangeIterator const& rhs) const { + return !(*this == rhs); + } + + bool operator<(RangeIterator const& rhs) const { + return std::tie(m_start, m_end, m_diff, m_current) < std::tie(rhs.m_start, rhs.m_end, rhs.m_diff, rhs.m_current); + } + + bool operator<=(RangeIterator const& rhs) const { + return (*this == rhs) || (*this < rhs); + } + + bool operator>=(RangeIterator const& rhs) const { + return !(*this < rhs); + } + + bool operator>(RangeIterator const& rhs) const { + return !(*this <= rhs); + } + + RangeIterator begin() const { + return RangeIterator(m_start, m_end, m_diff); + } + + RangeIterator end() const { + Diff steps = stepsBetween(m_start, m_end); + RangeIterator res(m_start, m_end, m_diff); + res += steps; + return res; + } + +private: + void copy(RangeIterator const& copy) { + m_start = copy.m_start; + m_end = copy.m_end; + m_diff = copy.m_diff; + m_current = copy.m_current; + m_stop = copy.m_stop; + sanity(); + } + + void sanity() { + if (m_diff == 0) + throw RangeException("Invalid difference in range function."); + + if ((m_end < m_start) != (RangeHelper::checkIfDiffLessThanZero<Diff>(m_diff))) { + if (RangeHelper::checkIfDiffLessThanZero<Diff>(m_diff)) + throw RangeException("Start cannot be less than end if diff is negative."); + throw RangeException("Max cannot be less than min."); + } + + if (m_end == m_start) + m_stop = true; + } + + bool sameClass(RangeIterator const& rhs) const { + return m_start == rhs.m_start && m_end == rhs.m_end && m_diff == rhs.m_diff; + } + + Diff stepsBetween(Value start, Value end) const { + return ((Diff)end - (Diff)start) / m_diff; + } + + Value applySteps(Value start, Diff travel) const { + return (Value)((Diff)start + travel); + } + + Value m_start; + Value m_end; + Diff m_diff; + + Value m_current; + + bool m_stop; +}; + +template <typename Numeric, typename Diff> +RangeIterator<Numeric, Diff> range(Numeric min, Numeric max, Diff diff) { + return RangeIterator<Numeric, Diff>(min, max, diff); +} + +template <typename Numeric, typename Diff = int> +RangeIterator<Numeric, Diff> range(Numeric max) { + return RangeIterator<Numeric, Diff>(max); +} + +template <typename Numeric, typename Diff = int> +RangeIterator<Numeric, Diff> range(Numeric min, Numeric max) { + return RangeIterator<Numeric, Diff>(min, max); +} + +template <typename Numeric, typename Diff> +RangeIterator<Numeric, Diff> rangeInclusive(Numeric min, Numeric max, Diff diff) { + return RangeIterator<Numeric, Diff>(min, (Numeric)((Diff)max + 1), diff); +} + +template <typename Numeric, typename Diff = int> +RangeIterator<Numeric, Diff> rangeInclusive(Numeric max) { + return RangeIterator<Numeric, Diff>((Numeric)((Diff)max + 1)); +} + +template <typename Numeric, typename Diff = int> +RangeIterator<Numeric, Diff> rangeInclusive(Numeric min, Numeric max) { + return RangeIterator<Numeric, Diff>(min, (Numeric)((Diff)max + 1)); +} + +// END RANGE + +// Wraps a forward-iterator to produce {value, index} pairs, similar to +// python's enumerate() +template <typename Iterator> +struct EnumerateIterator { +private: + Iterator current; + Iterator last; + size_t index; + bool atEnd; + +public: + typedef decltype(*std::declval<Iterator>()) IteratorValue; + typedef pair<IteratorValue&, size_t> value_type; + + EnumerateIterator() : index(0), atEnd(true) {} + + EnumerateIterator(Iterator begin, Iterator end) : current(begin), last(end), index(0) { + atEnd = current == last; + } + + EnumerateIterator begin() const { + return *this; + } + + EnumerateIterator end() const { + return EnumerateIterator(); + } + + EnumerateIterator operator++() { + if (!atEnd) { + ++current; + ++index; + + atEnd = current == last; + } + + return *this; + } + + value_type operator*() const { + return {*current, index}; + } + + bool operator==(EnumerateIterator const& rhs) const { + return (atEnd && rhs.atEnd) || (!atEnd && !rhs.atEnd && current == rhs.current && last == rhs.last); + } + + bool operator!=(EnumerateIterator const& rhs) const { + return !(*this == rhs); + } + + explicit operator bool() const { + return !atEnd; + } +}; + +template <typename Iterable> +EnumerateIterator<decltype(std::declval<Iterable>().begin())> enumerateIterator(Iterable& list) { + return EnumerateIterator<decltype(std::declval<Iterable>().begin())>(list.begin(), list.end()); +} + +template <typename ResultContainer, typename Iterable> +ResultContainer enumerateConstruct(Iterable&& list) { + ResultContainer res; + for (auto el : enumerateIterator(list)) + res.push_back(move(el)); + + return res; +} + +} + +#endif |