Last active
August 29, 2015 14:26
-
-
Save a4lg/7f82fdb786e30af36219 to your computer and use it in GitHub Desktop.
Change iterator type to input iterator, make dereference operator to return value again
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
int_range.hpp | |
Integral range generator (for C++11/14) | |
Copyright(C) 2015 Tsukasa OI. | |
Permission to use, copy, modify, and/or distribute this software for | |
any purpose with or without fee is hereby granted, provided that the | |
above copyright notice and this permission notice appear in all copies. | |
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
*/ | |
#ifndef A4LG_INT_RANGE_HPP | |
#define A4LG_INT_RANGE_HPP | |
#include <iterator> | |
#include <stdexcept> | |
#ifndef A4LG_CXX14_CONSTEXPR | |
#if __cpp_constexpr >= 201304L | |
#define A4LG_CXX14_CONSTEXPR constexpr | |
#else | |
#define A4LG_CXX14_CONSTEXPR | |
#endif | |
#endif | |
#ifndef USE_DEBUG_ITERATOR | |
#define A4LG_L_NOEXCEPT noexcept | |
#define A4LG_L_CONSTEXPR constexpr | |
#else | |
#define A4LG_L_NOEXCEPT | |
#define A4LG_L_CONSTEXPR A4LG_CXX14_CONSTEXPR | |
#endif | |
/* | |
Example: | |
for (int i : a4lg::int_range<int>(0, 10)) | |
// ... loop i from 0 to 9 (10 is excluded) | |
for (int i : a4lg::int_range_incl<int>(0, 10)) | |
// ... loop i from 0 to 10 (10 is included) | |
for (auto i : a4lg::int_range_incl<short>( | |
std::numeric_limits<short>::min(), | |
std::numeric_limits<short>::max() | |
)) | |
// scan through all `short' values | |
*/ | |
namespace a4lg | |
{ | |
// [begin, end) (`end' is excluded) | |
template <typename T> | |
class int_range | |
{ | |
T v_begin; | |
T v_end; | |
public: | |
class iterator | |
: public std::iterator< | |
std::input_iterator_tag, T, void, void, const T | |
> | |
{ | |
private: | |
T value; | |
#ifdef USE_DEBUG_ITERATOR | |
T v_begin; | |
T v_end; | |
#endif | |
private: | |
constexpr iterator( | |
T value | |
#ifdef USE_DEBUG_ITERATOR | |
, T vbegin | |
, T vend | |
#endif | |
) noexcept | |
: value(value) | |
#ifdef USE_DEBUG_ITERATOR | |
, v_begin(vbegin) | |
, v_end(vend) | |
#endif | |
{ | |
} | |
friend class int_range; | |
public: | |
constexpr iterator(const iterator&) noexcept = default; | |
A4LG_L_CONSTEXPR const T operator*(void) const A4LG_L_NOEXCEPT | |
{ | |
#ifdef USE_DEBUG_ITERATOR | |
if (value == v_end) | |
throw std::out_of_range("cannot read the value of the end."); | |
#endif | |
return value; | |
} | |
public: | |
A4LG_CXX14_CONSTEXPR iterator& operator++(void) A4LG_L_NOEXCEPT | |
{ | |
#ifdef USE_DEBUG_ITERATOR | |
if (value == v_end) | |
throw std::out_of_range("the iterator reached beyond the end."); | |
#endif | |
++value; | |
return *this; | |
} | |
A4LG_CXX14_CONSTEXPR iterator operator++(int) A4LG_L_NOEXCEPT | |
{ | |
#ifdef USE_DEBUG_ITERATOR | |
if (value == v_end) | |
throw std::out_of_range("the iterator reached beyond the end."); | |
#endif | |
iterator i(*this); | |
++value; | |
return i; | |
} | |
public: | |
A4LG_L_CONSTEXPR bool operator==(const iterator& other) const A4LG_L_NOEXCEPT | |
{ | |
#ifdef USE_DEBUG_ITERATOR | |
if (v_begin != other.v_begin || v_end != other.v_end) | |
throw std::invalid_argument("cannot compare two iterators with different ranges."); | |
#endif | |
return value == other.value; | |
} | |
A4LG_L_CONSTEXPR bool operator!=(const iterator& other) const A4LG_L_NOEXCEPT | |
{ | |
return !(operator==(other)); | |
} | |
}; | |
public: | |
constexpr int_range(T vbegin, T vend) | |
: v_begin(vbegin) | |
, v_end(vbegin <= vend ? vend | |
: throw std::invalid_argument("vend must not be larger than vbegin.")) | |
{ | |
} | |
public: | |
constexpr iterator begin(void) const noexcept | |
{ | |
return iterator(v_begin | |
#ifdef USE_DEBUG_ITERATOR | |
, v_begin, v_end | |
#endif | |
); | |
} | |
constexpr iterator end(void) const noexcept | |
{ | |
return iterator(v_end | |
#ifdef USE_DEBUG_ITERATOR | |
, v_begin, v_end | |
#endif | |
); | |
} | |
}; | |
// [begin, end] (`end' is included) | |
template <typename T> | |
class int_range_incl | |
{ | |
T v_begin; | |
T v_end; | |
public: | |
class iterator | |
: public std::iterator< | |
std::input_iterator_tag, T, void, void, const T | |
> | |
{ | |
private: | |
T value; | |
#ifdef USE_DEBUG_ITERATOR | |
T v_begin; | |
#endif | |
T v_end; | |
bool is_end; | |
private: | |
constexpr iterator( | |
T value | |
#ifdef USE_DEBUG_ITERATOR | |
, T vbegin | |
#endif | |
, T vend | |
, bool is_end | |
) noexcept | |
: value(value) | |
#ifdef USE_DEBUG_ITERATOR | |
, v_begin(vbegin) | |
#endif | |
, v_end(vend) | |
, is_end(is_end) | |
{ | |
} | |
friend class int_range_incl; | |
public: | |
constexpr iterator(const iterator&) noexcept = default; | |
A4LG_L_CONSTEXPR const T operator*(void) const A4LG_L_NOEXCEPT | |
{ | |
#ifdef USE_DEBUG_ITERATOR | |
if (value == v_end && is_end) | |
throw std::out_of_range("cannot read the value of the end."); | |
#endif | |
return value; | |
} | |
public: | |
A4LG_CXX14_CONSTEXPR iterator& operator++(void) A4LG_L_NOEXCEPT | |
{ | |
#ifdef USE_DEBUG_ITERATOR | |
if (value == v_end && is_end) | |
throw std::out_of_range("the iterator reached beyond the end."); | |
#endif | |
if (value == v_end) | |
is_end = true; | |
else | |
++value; | |
return *this; | |
} | |
A4LG_CXX14_CONSTEXPR iterator operator++(int) A4LG_L_NOEXCEPT | |
{ | |
#ifdef USE_DEBUG_ITERATOR | |
if (value == v_end && is_end) | |
throw std::out_of_range("the iterator reached beyond the end."); | |
#endif | |
iterator i(*this); | |
if (value == v_end) | |
is_end = true; | |
else | |
++value; | |
return i; | |
} | |
public: | |
A4LG_L_CONSTEXPR bool operator==(const iterator& other) const A4LG_L_NOEXCEPT | |
{ | |
#ifdef USE_DEBUG_ITERATOR | |
if (v_begin != other.v_begin || v_end != other.v_end) | |
throw std::invalid_argument("cannot compare two iterators with different ranges."); | |
#endif | |
return (is_end == other.is_end) && (is_end || (value == other.value)); | |
} | |
A4LG_L_CONSTEXPR bool operator!=(const iterator& other) const A4LG_L_NOEXCEPT | |
{ | |
return !(operator==(other)); | |
} | |
}; | |
public: | |
constexpr int_range_incl(T vbegin, T vend) | |
: v_begin(vbegin) | |
, v_end(vbegin <= vend ? vend | |
: throw std::invalid_argument("vend must not be larger than vbegin.")) | |
{ | |
} | |
public: | |
constexpr iterator begin(void) const noexcept | |
{ | |
return iterator(v_begin | |
#ifdef USE_DEBUG_ITERATOR | |
, v_begin | |
#endif | |
, v_end, false | |
); | |
} | |
constexpr iterator end(void) const noexcept | |
{ | |
return iterator(v_end | |
#ifdef USE_DEBUG_ITERATOR | |
, v_begin | |
#endif | |
, v_end, true | |
); | |
} | |
}; | |
} | |
#undef A4LG_L_NOEXCEPT | |
#undef A4LG_L_CONSTEXPR | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment