Skip to content

Commit

Permalink
Fix take_view
Browse files Browse the repository at this point in the history
  • Loading branch information
lackhole committed Jun 23, 2024
1 parent 4010c47 commit a7cd16c
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 30 deletions.
69 changes: 39 additions & 30 deletions include/preview/__ranges/views/take.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <type_traits>

#include "preview/__core/decay_copy.h"
#include "preview/__core/std_version.h"
#include "preview/__concepts/convertible_to.h"
#include "preview/__ranges/begin.h"
#include "preview/__ranges/end.h"
Expand All @@ -26,12 +27,20 @@
#include "preview/__ranges/views/take_view.h"
#include "preview/span.h"
#include "preview/string_view.h"
#include "preview/__type_traits/conditional.h"
#include "preview/__type_traits/detail/return_category.h"
#include "preview/__type_traits/is_specialization.h"
#include "preview/__type_traits/negation.h"
#include "preview/__type_traits/remove_cvref.h"
#include "preview/__type_traits/type_identity.h"

#if PREVIEW_CXX_VERSION >= 17
#include <string_view>
#endif
#if PREVIEW_CXX_VERSION >= 20
#include <span>
#endif

namespace preview {
namespace ranges {
namespace views {
Expand All @@ -54,21 +63,27 @@ struct take_niebloid {
return ((void)count, preview_decay_copy(std::forward<R>(r)));
}

template<typename T>
struct is_span : std::false_type {};
template<typename T, std::size_t Extent>
struct is_span<span<T, Extent>> : std::true_type {};

template<typename T, typename D, bool = is_span<T>::value /* true */>
struct return_category_span : std::true_type {
using category = return_category<2, span<typename T::element_type>>;
};
template<typename T, typename D>
struct return_category_span<T, D, false> : std::false_type {
struct return_category_span : std::false_type {
using category = return_category<0>;
};

template<typename T, bool = is_specialization<T, basic_string_view>::value /* true */>
template<typename U, std::size_t Extent, typename D>
struct return_category_span<span<U, Extent>, D> : std::true_type {
using category = return_category<2, span<U>>;
};
#if PREVIEW_CXX_VERSION >= 20
template<typename U, std::size_t Extent, typename D>
struct return_category_span<std::span<U, Extent>, D> : std::true_type {
using category = return_category<2, std::span<U>>;
};
#endif

template<typename T, bool = disjunction<
is_specialization<T, basic_string_view>
#if PREVIEW_CXX_VERSION >= 17
, is_specialization<T, std::basic_string_view>
#endif
>::value /* true */>
struct return_category_string_view : std::true_type {
using category = return_category<2, T>;
};
Expand All @@ -77,7 +92,7 @@ struct take_niebloid {
using category = return_category<0>;
};

template<typename T, bool = ranges::detail::is_subrange<T>::value /* true */>
template<typename T, bool = conjunction<ranges::detail::is_subrange<T>, random_access_range<T>, sized_range<T>>::value /* true */>
struct return_category_subrange : std::true_type {
using category = return_category<2, subrange<iterator_t<T>>>;
};
Expand All @@ -103,8 +118,8 @@ struct take_niebloid {
struct return_category_iota_view<T, false> : std::false_type {
using category = return_category<0>;
};
template<typename R, typename IV>
constexpr IV operator()(R&& e, ranges::range_difference_t<R> f, return_category<3, IV>) const {
template<typename R, typename T>
constexpr auto operator()(R&& e, ranges::range_difference_t<R> f, return_category<3, T /* unused */>) const {
using D = ranges::range_difference_t<decltype((e))>;
return views::iota(
*ranges::begin(e),
Expand Down Expand Up @@ -138,21 +153,15 @@ struct take_niebloid {

template<typename R, typename T, typename D>
using category =
std::conditional_t<
return_category_empty_view<R, T, D>::value, typename return_category_empty_view<R, T, D>::category, // 1
std::conditional_t<
return_category_span<T, D>::value, typename return_category_span<T, D>::category, // 2
std::conditional_t<
return_category_string_view<T>::value, typename return_category_string_view<T>::category, // 2
std::conditional_t<
return_category_subrange<T>::value, typename return_category_subrange<T>::category, // 2
std::conditional_t<
return_category_iota_view<T>::value, typename return_category_iota_view<T>::category, // 3
std::conditional_t<
return_category_repeat_view<T>::value, typename return_category_repeat_view<T>::category, // 4
return_category<5, take_view<views::all_t<R>>>> // 5
>>>>>;

conditional_t<
return_category_empty_view<R, T, D>, typename return_category_empty_view<R, T, D>::category, // 1
return_category_span<T, D>, typename return_category_span<T, D>::category, // 2
return_category_string_view<T>, typename return_category_string_view<T>::category, // 2
return_category_subrange<T>, typename return_category_subrange<T>::category, // 2
return_category_iota_view<T>, typename return_category_iota_view<T>::category, // 3
return_category_repeat_view<T>, typename return_category_repeat_view<T>::category, // 4
return_category<5, take_view<views::all_t<R>>> // 5
>;

public:
template<typename R, std::enable_if_t<ranges::viewable_range<R>::value, int> = 0>
Expand Down
109 changes: 109 additions & 0 deletions test/ranges_views.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include "preview/algorithm.h"
#include "preview/concepts.h"
#include "preview/functional.h"
#include "preview/span.h"
#include "preview/string_view.h"

Expand Down Expand Up @@ -414,3 +415,111 @@ TEST(VERSIONED(RangesViews), transform_view) {
EXPECT_TRUE(ranges::equal(out | views::transform(rot13), "cppreference.com\n"s));
#endif
}

template<typename F, typename BoundArgs>
struct my_bind_front {
template<typename... T>
my_bind_front(F f, T&&... args)
: f_(std::move(f))
, front_(std::forward_as_tuple(std::forward<T>(args)...)) {}

template<typename... Args>
decltype(auto) operator()(Args&&... args) {
return call(preview::tuple_index_sequence<BoundArgs>{}, std::forward<Args>(args)...);
}

template<std::size_t... I, typename... Args>
decltype(auto) call(std::index_sequence<I...>, Args&&... args) {
return f_(std::get<I>(front_)..., std::forward<Args>(args)...);
}

F f_;
BoundArgs front_;
};

TEST(VERSIONED(RangesViews), take_view) {
using namespace std::literals;
using namespace preview::literals;

{ // begin 1
static constexpr auto v = {"Ax"_sv, "By"_sv, "c"_sv, "d"_sv};
#if PREVIEW_CXX_VERSION >= 17
auto view = ranges::take_view(v, 8);
#else
auto view = views::take(v, 8);
#endif
auto iter = view.begin();
EXPECT_EQ(*iter, "Ax"_sv);

EXPECT_TRUE_TYPE(ranges::sized_range<decltype(v)>);
EXPECT_TRUE_TYPE(ranges::random_access_range<decltype(v)>);
EXPECT_TRUE_TYPE(std::is_same<decltype(iter), decltype(ranges::begin(v))>);
}
{ // begin 2
{
std::forward_list<preview::string_view> v = {"Ax"_sv, "Ey"_sv, "p"_sv, "q"_sv};
#if PREVIEW_CXX_VERSION >= 17
auto view = ranges::take_view(v, 8);
#else
auto view = views::take(v, 8);
#endif
auto iter = view.begin();
EXPECT_EQ(*iter, "Ax"_sv);

EXPECT_FALSE_TYPE(ranges::sized_range<decltype(v)>);
EXPECT_FALSE_TYPE(ranges::random_access_range<decltype(v)>);
EXPECT_TRUE_TYPE(std::is_same<
decltype(iter),
preview::counted_iterator<std::forward_list<preview::string_view>::iterator>
>);
}
}

{ // end
const auto list1 = {3, 1, 4, 1, 5};
const auto seq1 = list1 | views::take(4);

EXPECT_TRUE_TYPE(ranges::sized_range<decltype(seq1)>);
EXPECT_TRUE_TYPE(ranges::random_access_range<decltype(seq1)>);
EXPECT_TRUE_TYPE(std::is_same<decltype(seq1.end()), decltype(list1.end())>);

for (auto it = seq1.begin(); it != seq1.end(); ++it) { (void)*it; }
EXPECT_TRUE(ranges::equal(seq1, {3, 1, 4, 1}));

std::list<int> list2 = {2, 7, 1, 8, 2};
const auto seq2 = list2 | views::take(4);
EXPECT_TRUE_TYPE (ranges::sized_range<decltype(seq2)>);
EXPECT_FALSE_TYPE(ranges::random_access_range<decltype(seq2)>);
EXPECT_TRUE_TYPE (std::is_same<decltype(seq2.end()), preview::default_sentinel_t>);

for (auto it = seq2.begin(); it != preview::default_sentinel; ++it) { (void)*it; }
EXPECT_TRUE(ranges::equal(seq2, {2, 7, 1, 8}));
}

{ // size
constexpr int arr[]{1, 2, 3};
EXPECT_TRUE(ranges::equal(
views::iota(0, 6) | views::transform(preview::bind_front(views::take, arr)),
{0, 1, 2, 3, 3, 3},
{},
[](auto&& tv) { return tv.size(); }
));
}

constexpr char pi[]{'3', '.', '1', '4', '1', '5', '9', '2'};

std::string out;
auto print = [&](char x){ out.push_back(x); };

ranges::for_each(pi | views::take(6), print);
EXPECT_EQ(out, "3.1415"s);

// safely takes 8 chars only, i.e. min(pi.size(), 42)
out.clear();
#if PREVIEW_CXX_VERSION >= 17
ranges::for_each(ranges::take_view{pi, 42}, print);
#else
ranges::for_each(views::take(pi, 42), print);
#endif
EXPECT_EQ(out, "3.141592");
}

0 comments on commit a7cd16c

Please sign in to comment.