1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
| #include <cmath>
#include <type_traits>
namespace range_impl {
template<typename T>
struct range_t;
template<typename T>
struct has_size_t {
template <typename U> static std::true_type dummy(typename std::decay<
decltype(std::declval<U&>().size())>::type*);
template <typename U> static std::false_type dummy(...);
using type = decltype(dummy<T>(0));
};
template<typename T>
using has_size = typename has_size_t<T>::type;
template<typename T, bool integral>
struct dtype_impl;
template <typename T>
struct dtype_impl<T,true> {
using type = typename std::make_signed<T>::type;
};
template <typename T>
struct dtype_impl<T,false> {
using type = T;
};
template<typename T>
using dtype = typename dtype_impl<T, std::is_integral<T>::value>::type;
template <typename T>
dtype<T> make_step(dtype<T> e, dtype<T> b, dtype<T> n) {
return (e-b)/n;
}
template<typename T>
struct iterator_t;
template<typename T>
struct iterator_t<range_t<T>> {
const range_t<T>& range;
std::size_t i;
iterator_t& operator++ (int) {
++i;
return *this;
}
iterator_t operator++ () {
return iterator_t{range, i++};
}
T operator * () const {
return range.b + range.d*i;
}
bool operator == (const iterator_t& iter) const {
return iter.i == i && &iter.range == ⦥
}
bool operator != (const iterator_t& iter) const {
return iter.i != i || &iter.range != ⦥
}
};
template<typename T>
struct range_t {
T b, e;
dtype<T> d;
std::size_t n;
explicit range_t(T b_, T e_, std::size_t n_) : b(b_), e(e_),
d(n_ == 0 ? 0 : make_step<T>(e_, b_, n_)), n(n_) {}
using iterator = iterator_t<range_t>;
iterator begin() const { return iterator{*this, 0}; }
iterator end() const { return iterator{*this, n}; }
};
}
// Define a range from start 'i', end 'e' (exclusive), and number of steps 'n'
template<typename T, typename U = T>
range_impl::range_t<T> range(T i, U e, std::size_t n) {
return range_impl::range_t<T>(i, e, n);
}
// Define a range from start 'i', end 'e' (exclusive) in integer steps
template<typename T, typename U = T, typename enable = typename std::enable_if<std::is_integral<T>::value>::type>
range_impl::range_t<T> range(T i, U e) {
return range(i, e, std::abs(range_impl::dtype<T>(e)-range_impl::dtype<T>(i)));
}
// Define a range from '0' to 'n' (exclusive) in integer steps
template<typename T, typename enable = typename std::enable_if<std::is_integral<T>::value>::type>
range_impl::range_t<T> range(T n) {
return range(T(0), n);
}
// Define a range from '0' to 'n.size()' (exclusive) in integer steps
template<typename T, typename enable = typename std::enable_if<range_impl::has_size<T>::value>::type>
auto range(const T& n) -> range_impl::range_t<decltype(n.size())> {
return range(n.size());
} |