#ifndef STAR_PYTHONIC_HPP #define STAR_PYTHONIC_HPP #include "StarAlgorithm.hpp" namespace Star { // any and all template bool any(Iterator iterBegin, Iterator iterEnd, Functor const& f) { for (; iterBegin != iterEnd; iterBegin++) if (f(*iterBegin)) return true; return false; } template bool any(Iterator const& iterBegin, Iterator const& iterEnd) { typedef typename std::iterator_traits::value_type IteratorValue; std::function compare = [](IteratorValue const& i) { return (bool)i; }; return any(iterBegin, iterEnd, compare); } template bool any(Iterable const& iter, Functor const& f) { return any(std::begin(iter), std::end(iter), f); } template bool any(Iterable const& iter) { typedef decltype(*std::begin(iter)) IteratorValue; std::function compare = [](IteratorValue const& i) { return (bool)i; }; return any(std::begin(iter), std::end(iter), compare); } template bool all(Iterator iterBegin, Iterator iterEnd, Functor const& f) { for (; iterBegin != iterEnd; iterBegin++) if (!f(*iterBegin)) return false; return true; } template bool all(Iterator const& iterBegin, Iterator const& iterEnd) { typedef typename std::iterator_traits::value_type IteratorValue; std::function compare = [](IteratorValue const& i) { return (bool)i; }; return all(iterBegin, iterEnd, compare); } template bool all(Iterable const& iter, Functor const& f) { return all(std::begin(iter), std::end(iter), f); } template bool all(Iterable const& iter) { typedef decltype(*std::begin(iter)) IteratorValue; std::function 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 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 T slice(T const& r, SliceIndex a, SliceIndex b = SliceIndex(), int j = 1) { return slice(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 class ZipWrapperIterator { private: IteratorT current; IteratorT last; bool atEnd; public: typedef IteratorT Iterator; typedef decltype(*std::declval()) IteratorValue; typedef tuple 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(*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 ZipWrapperIterator makeZipWrapperIterator(IteratorT current, IteratorT end) { return ZipWrapperIterator(current, end); } // Takes two ZipIterators / ZipTupleIterators and concatenates them into a // single iterator that returns the concatenated tuple. template 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(), std::declval())) 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 ZipTupleIterator makeZipTupleIterator(HeadIteratorT head, TailIteratorT tail) { return ZipTupleIterator(head, tail); } template struct zipIteratorReturn { typedef ZipTupleIterator::type, typename zipIteratorReturn::type> type; }; template struct zipIteratorReturn { typedef ZipWrapperIterator().begin())> type; }; template typename zipIteratorReturn::type zipIterator(Container& container) { return makeZipWrapperIterator(container.begin(), container.end()); } template typename zipIteratorReturn::type zipIterator(Container& container, Rest&... rest) { return makeZipTupleIterator(makeZipWrapperIterator(container.begin(), container.end()), zipIterator(rest...)); } // END ZIP // RANGE namespace RangeHelper { template typename std::enable_if::value, bool>::type checkIfDiffLessThanZero(Diff) { return false; } template typename std::enable_if::value, bool>::type checkIfDiffLessThanZero(Diff diff) { return diff < 0; } } STAR_EXCEPTION(RangeException, StarException); template class RangeIterator : public std::iterator { 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(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(m_diff))) { if (RangeHelper::checkIfDiffLessThanZero(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 RangeIterator range(Numeric min, Numeric max, Diff diff) { return RangeIterator(min, max, diff); } template RangeIterator range(Numeric max) { return RangeIterator(max); } template RangeIterator range(Numeric min, Numeric max) { return RangeIterator(min, max); } template RangeIterator rangeInclusive(Numeric min, Numeric max, Diff diff) { return RangeIterator(min, (Numeric)((Diff)max + 1), diff); } template RangeIterator rangeInclusive(Numeric max) { return RangeIterator((Numeric)((Diff)max + 1)); } template RangeIterator rangeInclusive(Numeric min, Numeric max) { return RangeIterator(min, (Numeric)((Diff)max + 1)); } // END RANGE // Wraps a forward-iterator to produce {value, index} pairs, similar to // python's enumerate() template struct EnumerateIterator { private: Iterator current; Iterator last; size_t index; bool atEnd; public: typedef decltype(*std::declval()) IteratorValue; typedef pair 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 EnumerateIterator().begin())> enumerateIterator(Iterable& list) { return EnumerateIterator().begin())>(list.begin(), list.end()); } template ResultContainer enumerateConstruct(Iterable&& list) { ResultContainer res; for (auto el : enumerateIterator(list)) res.push_back(move(el)); return res; } } #endif