Skip to content
Snippets Groups Projects
Commit 0074d9a2 authored by Vasileios Karakasis's avatar Vasileios Karakasis
Browse files

Addresses PR review comments.

Adds support to call `std:distance()` in cases where a valid conversion
between iterator and sentinel exists.
parent 8005cada
No related branches found
No related tags found
No related merge requests found
......@@ -43,16 +43,19 @@ upto(I iter, E end) {
return iter==I{end}? iter: I{std::prev(end)};
}
template <typename I, typename E>
enable_if_t<std::is_same<I, E>::value && is_forward_iterator<I>::value,
typename std::iterator_traits<I>::difference_type>
template <typename I, typename E,
typename C = typename common_random_access_iterator<I,E>::type>
enable_if_t<std::is_same<I, E>::value ||
(has_common_random_access_iterator<I,E>::value &&
is_forward_iterator<I>::value),
typename std::iterator_traits<C>::difference_type>
distance(I first, E last) {
return std::distance(first, last);
return std::distance(static_cast<C>(first), static_cast<C>(last));
}
template <typename I, typename E>
enable_if_t<!std::is_same<I, E>::value && is_forward_iterator<I>::value,
enable_if_t<!has_common_random_access_iterator<I, E>::value &&
is_forward_iterator<I>::value,
typename std::iterator_traits<I>::difference_type>
distance(I first, E last) {
typename std::iterator_traits<I>::difference_type ret = 0;
......
......@@ -151,6 +151,36 @@ struct is_forward_iterator<T, enable_if_t<
template <typename T>
using is_forward_iterator_t = typename is_forward_iterator<T>::type;
template <typename I, typename E, typename = void, typename = void>
struct common_random_access_iterator {};
template <typename I, typename E>
struct common_random_access_iterator<
I,
E,
void_t<decltype(false ? std::declval<I>() : std::declval<E>())>,
enable_if_t<
is_random_access_iterator<
decay_t<decltype(false ? std::declval<I>() : std::declval<E>())>
>::value
>
> {
using type = decay_t<
decltype(false ? std::declval<I>() : std::declval<E>())
>;
};
template <typename I, typename E, typename = void>
struct has_common_random_access_iterator: public std::false_type {};
template <typename I, typename E>
struct has_common_random_access_iterator<
I, E, void_t<typename common_random_access_iterator<I, E>::type>
> : public std::true_type {};
} // namespace util
} // namespace mc
} // namespace nest
......@@ -12,6 +12,7 @@
#endif
#include <util/counter.hpp>
#include <util/meta.hpp>
#include <util/range.hpp>
#include <util/sentinel.hpp>
......@@ -20,7 +21,7 @@ using namespace nest::mc;
TEST(range, list_iterator) {
std::list<int> l = { 2, 4, 6, 8, 10 };
auto s = util::make_range(l.begin(), l.end());
auto s = util::make_range(l.begin(), l.end());
EXPECT_EQ(s.left, l.begin());
EXPECT_EQ(s.right, l.end());
......@@ -42,6 +43,10 @@ TEST(range, list_iterator) {
auto sum2 = std::accumulate(s.begin(), s.end(), 0);
EXPECT_EQ(check, sum2);
// Check that different begin/end iterators are treated correctly
auto sc = util::make_range(l.begin(), l.cend());
EXPECT_EQ(l.size(), sc.size());
}
TEST(range, pointer) {
......@@ -77,24 +82,54 @@ TEST(range, empty) {
auto l = 2;
auto r = 5;
auto empty_range_ll = util::make_range(&xs[l], &xs[l]);
auto empty_range_ll = util::make_range((const int *) &xs[l], &xs[l]);
EXPECT_TRUE(empty_range_ll.empty());
EXPECT_EQ(empty_range_ll.begin() == empty_range_ll.end(),
empty_range_ll.empty());
EXPECT_EQ(0u, empty_range_ll.size());
auto empty_range_rr = util::make_range(&xs[r], &xs[r]);
auto empty_range_rr = util::make_range(&xs[r], (const int *) &xs[r]);
EXPECT_TRUE(empty_range_rr.empty());
EXPECT_EQ(empty_range_rr.begin() == empty_range_rr.end(),
empty_range_rr.empty());
EXPECT_EQ(0u, empty_range_rr.size());
}
template<typename I, typename E, typename = void>
struct util_distance_enabled : public std::false_type {};
// This is the same test for enabling util::distance
template<typename I, typename E>
struct util_distance_enabled<
I, E, util::void_t<
util::enable_if_t<
!util::has_common_random_access_iterator<I, E>::value &&
util::is_forward_iterator<I>::value
>>> : public std::true_type {};
TEST(range, size) {
static_assert(util_distance_enabled<
typename std::list<int>::iterator,
typename std::list<int>::const_iterator>::value,
"util::distance not enabled");
static_assert(!util_distance_enabled<
typename std::vector<int>::const_iterator,
typename std::vector<int>::iterator>::value,
"util::distance erroneously enabled");
static_assert(!util_distance_enabled<int*, int*>::value,
"util::distance erroneously enabled");
static_assert(!util_distance_enabled<int*, const int*>::value,
"util::distance erroneously enabled");
static_assert(!util_distance_enabled<const int*, int*>::value,
"util::distance erroneously enabled");
}
TEST(range, input_iterator) {
int nums[] = { 10, 9, 8, 7, 6 };
std::istringstream sin("10 9 8 7 6");
auto s = util::make_range(std::istream_iterator<int>(sin), std::istream_iterator<int>());
auto s = util::make_range(std::istream_iterator<int>(sin),
std::istream_iterator<int>());
EXPECT_TRUE(std::equal(s.begin(), s.end(), &nums[0]));
}
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment