Skip to content

Instantly share code, notes, and snippets.

@gnzlbg
Created July 11, 2014 11:09
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 gnzlbg/db97be19ea35d025db1f to your computer and use it in GitHub Desktop.
Save gnzlbg/db97be19ea35d025db1f to your computer and use it in GitHub Desktop.
ranges::make for range-v3
////////////////////////////////////////////////////////////////////////////////
///
/// \file A make function for the range-v3 library that is able to construct
/// a range from:
/// - a pair of indices
/// - an index and a predicate
/// - a pair of iterators
/// - an iterator and a size
/// - an iterator and a predicate
/// - a container (not implemented yet since we can just use as_range)
///
/// Includes:
#include <range/v3/range.hpp>
////////////////////////////////////////////////////////////////////////////////
using namespace ranges;
namespace detail {
////////////////////////////////////////////////////////////////////////////////
/// Metafunctions to check if a type is an iterator, an index, or a
/// predicate:
/// A type T is an iterator if std::iterator_traits for T exist and its
/// value_type is not void
template<class T, class = void>
struct is_iterator : std::false_type {};
template<class T>
struct is_iterator<T,
typename std::enable_if<
!std::is_same<
typename std::iterator_traits<T>::value_type, void
>::value
>::type
>
: std::true_type {};
/// A type T is an index if std::is_integral is true
template<class T, class = void>
struct is_index : std::false_type {};
template<class T>
struct is_index<T,
typename std::enable_if<
std::is_integral<T>::value
>::type
>
: std::true_type {};
/// A type T is a predicate on U if T is callable with an U and returns a bool
template<class T, class U, class = void>
struct is_predicate : std::false_type {};
template<class T, class U>
struct is_predicate<T, U,
typename std::enable_if<
std::is_same<bool, decltype(std::declval<T>()(std::declval<U>()))>::value
>::type
>
: std::true_type {};
// A type T is a predicate on U if T is callable with an U and returns a bool
template<class T, class U, class = void>
struct is_iterator_predicate : std::false_type {};
template<class T, class U>
struct is_iterator_predicate<T, U,
typename std::enable_if<
std::is_same<bool, decltype(std::declval<T>()(*(std::declval<U>())))>::value
>::type
>
: std::true_type {};
/// A pair of types T,U are an iterator pair if both are iterators of the same
/// type
template<class T, class U, class = void>
struct is_iterator_pair : std::false_type {};
template<class T, class U>
struct is_iterator_pair<T, U,
typename std::enable_if<
is_iterator<T>::value && is_iterator<U>::value
&& std::is_same<T, U>::value
>::type
>
: std::true_type {};
/// A pair of types T,U are an indexpair if both are indices of the same type
template<class T, class U, class = void>
struct is_index_pair : std::false_type {};
template<class T, class U>
struct is_index_pair<T, U,
typename std::enable_if<
is_index<T>::value && is_index<U>::value
&& std::is_same<T, U>::value
>::type
>
: std::true_type {};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// Tags to select how to construct a range:
struct index_pair {};
struct index_and_predicate {};
struct iterator_pair {};
struct iterator_and_predicate {};
struct iterator_and_distance {};
struct cannot_construct_range_from_given_types {};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// Trait to dispatch to the right constructor function
template <class T, class U, class = void>
struct dispatch { using type = cannot_construct_range_from_given_types; };
/// Build range from two indices: [begin, end)
template <class IndexBegin, class IndexEnd>
struct dispatch<IndexBegin, IndexEnd,
typename std::enable_if<
is_index_pair<IndexBegin, IndexEnd>::value
>::type
> { using type = index_pair; };
/// Build range from index and predicate:
template <class IndexBegin, class IndexPredicate>
struct dispatch<IndexBegin, IndexPredicate,
typename std::enable_if<
is_index<IndexBegin>::value &&
is_predicate<IndexBegin, IndexPredicate>::value
>::type
> { using type = index_and_predicate; };
/// Build range from two iterators: [begin, end)
template <class ItBegin, class ItEnd>
struct dispatch<ItBegin, ItEnd,
typename std::enable_if<
is_iterator_pair<ItBegin, ItEnd>::value
>::type
> { using type = iterator_pair; };
/// Build range from iterator and predicate
template <class It, class ItPredicate>
struct dispatch<It, ItPredicate,
typename std::enable_if<
is_iterator<It>::value &&
is_iterator_predicate<It, ItPredicate>::value
>::type
> { using type = iterator_and_predicate; };
/// Build range from iterator and distance type
template <class It, class DistanceType>
struct dispatch<It, DistanceType,
typename std::enable_if<
is_iterator<It>::value && is_index<DistanceType>::value
>::type
> { using type = iterator_and_distance; };
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// Range constructor functions
/// Make range from two indices: [b, e)
template <class Index>
auto make_range(Index&& b, Index&& e, index_pair) {
return view::take(view::iota(std::forward<Index>(b)),
std::forward<Index>(e - b));
}
/// Make range from index b until predicate returns false
template <class Index, class Predicate>
auto make_range(Index&& b, Predicate&& p, index_and_predicate) {
// return view::while_true(view::iota(std::forward<Index>(b)),
// std::forward<Predicate>(p));
}
/// Make range from an iterator pair [b, e)
template <class It>
auto make_range(It&& b, It&& e, iterator_pair) {
return iterator_range<It>{std::forward<It>(b), std::forward<It>(e)};
}
/// Make range from an iterator and a distance
template <class It, class Distance>
auto make_range(It&& b, Distance&& d, iterator_and_distance) {
/// TODO: sized_iterator_range cannot be constructed from a single it and a
/// size yet, the following might be inefficient for
/// iterator_category < random_access_iterator
auto e = b;
return iterator_range<It>{std::forward<It>(b), std::advance(e, d)};
}
/// Make range from an iterator b, and a predicate p
template <class It, class Predicate>
auto make_range(It&& b, Predicate&& p, iterator_and_predicate) {
/// TODO: not implemented yet
}
} // namespace detail
template <class T, class U> auto make(T&& t, U&& u) {
return detail::make_range(std::forward<T>(t), std::forward<U>(u),
typename detail::dispatch<T, U>::type{});
}
////////////////////////////////////////////////////////////////////////////////
int main() {
int a = 0;
int b = 10;
static_assert(std::is_integral<decltype(a)>::value, "");
static_assert(range::detail::is_index<decltype(a)>::value, "");
// integer pair
auto irange = make(0, 10);
for (auto&& i : irange) {
std::cout << i << std::endl;
}
// iterator pair
std::vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
auto itrange = make(std::begin(v), std::end(v));
for (auto&& i : itrange) {
std::cout << i << std::endl;
}
// pointer pair
auto prange = make(&(*std::begin(v)), &(*std::begin(v)) + 10);
for (auto&& i : prange) {
std::cout << i << std::endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment