Created
July 11, 2014 11:09
-
-
Save gnzlbg/db97be19ea35d025db1f to your computer and use it in GitHub Desktop.
ranges::make for range-v3
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
//////////////////////////////////////////////////////////////////////////////// | |
/// | |
/// \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