Skip to content

Instantly share code, notes, and snippets.

@a4lg
Last active August 29, 2015 14:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save a4lg/7f82fdb786e30af36219 to your computer and use it in GitHub Desktop.
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
/*
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