// // Copyright (C) 2011-15 DyND Developers // BSD 2-Clause License, see LICENSE.txt // #pragma once #include #include namespace dynd { /** * This class represents a range of indices, or a single index. * * The single index is indicated by a step of 0, in which case the * value of m_start is taken as that index. This form removes the * dimension it is indexing from the array. * * The range of indices is the set {m_start, m_start + m_step, ... * m_start + k * m_step} as large as possible where each element * is less than m_finish when m_step is positive, or greater than * m_finish when m_step is negative. * * The ways to construct this class do no error checking, in order * to fit the requirements of C++ DYND_CONSTEXPR. * * Typical ways to construct ranges are as follows: * * irange() // The full index range [begin, end) * 3 <= irange() // The index range [3, end) * 2 <= irange() < 10 // The index range [2, 10) * 1 < irange() < 5 // The index range [2, 5) * 3 <= irange().by(2) < 10 // The indices {3, 5, 7, 9} * * TODO: Should negative indices be supported with the meaning as in Python? */ class irange { intptr_t m_start, m_finish, m_step; public: inline /*DYND_CONSTEXPR*/ irange() : m_start(std::numeric_limits::min()), m_finish(std::numeric_limits::max()), m_step(1) { } inline DYND_CONSTEXPR irange(intptr_t idx) : m_start(idx), m_finish(idx), m_step(0) {} inline DYND_CONSTEXPR irange(intptr_t start, intptr_t finish, intptr_t step = 1) : m_start(start), m_finish(finish), m_step(step) { } inline DYND_CONSTEXPR const intptr_t &start() const { return m_start; } inline DYND_CONSTEXPR const intptr_t &finish() const { return m_finish; } inline DYND_CONSTEXPR const intptr_t &step() const { return m_step; } inline void set_start(intptr_t value) { m_start = value; } inline void set_finish(intptr_t value) { m_finish = value; } inline void set_step(intptr_t value) { m_step = value; } /** Returns true if this irange does nothing, e.g. [:] */ inline bool is_nop() const { return m_start == std::numeric_limits::min() && m_finish == std::numeric_limits::max() && m_step == 1; } /** * The notation "irange().by(step)" is a way to specify * the step of the range. */ DYND_CONSTEXPR irange by(intptr_t step) const { return irange(m_start, m_finish, step); } /** * The notation "irange() < finish" is a way to specify * the end of a range with a positive step. */ DYND_CONSTEXPR irange operator<(intptr_t finish) const { return irange(m_start, finish, m_step); } /** * The notation "irange() <= last" is a way to specify * the end of a range with a positive step. */ DYND_CONSTEXPR irange operator<=(intptr_t last) const { return irange(m_start, (last != -1) ? (last + 1) : std::numeric_limits::max(), m_step); } /** * The notation "irange() > finish" is a way to specify * the end of a range with a negative step. */ DYND_CONSTEXPR irange operator>(intptr_t finish) const { return irange(m_start, finish, m_step); } /** * The notation "irange() >= last" is a way to specify * the end of a range with a negative step. */ DYND_CONSTEXPR irange operator>=(intptr_t last) const { return irange(m_start, (last != 0) ? (last - 1) : std::numeric_limits::max(), m_step); } friend DYND_CONSTEXPR irange operator<(intptr_t start_minus_one, const irange &i); friend DYND_CONSTEXPR irange operator<=(intptr_t start, const irange &i); friend DYND_CONSTEXPR irange operator>(intptr_t start_plus_one, const irange &i); friend DYND_CONSTEXPR irange operator>=(intptr_t start, const irange &i); }; /** * The notation "lower < irange()" is a way to specify * the beginning of a range with a positive step. */ inline DYND_CONSTEXPR irange operator<(intptr_t start_minus_one, const irange &i) { return irange(start_minus_one + 1, i.m_finish, i.m_step); } /** * The notation "start <= irange()" is a way to specify * the beginning of a range with a positive step. */ inline DYND_CONSTEXPR irange operator<=(intptr_t start, const irange &i) { return irange(start, i.m_finish, i.m_step); } /** * The notation "upper > irange()" is a way to specify * the beginning of a range with a negative step. */ inline DYND_CONSTEXPR irange operator>(intptr_t start_plus_one, const irange &i) { return irange(start_plus_one - 1, i.m_finish, i.m_step); } /** * The notation "start >= irange()" is a way to specify * the beginning of a range with a negative step. */ inline DYND_CONSTEXPR irange operator>=(intptr_t start, const irange &i) { return irange(start, i.m_finish, i.m_step); } } // namespace dynd