From a7cd16cfeb029a62b69b2d12d213b5b58e369bfd Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Mon, 24 Jun 2024 03:00:29 +0900 Subject: [PATCH] Fix take_view --- include/preview/__ranges/views/take.h | 69 +++++++++------- test/ranges_views.cc | 109 ++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 30 deletions(-) diff --git a/include/preview/__ranges/views/take.h b/include/preview/__ranges/views/take.h index 5234f35..a33bcdf 100644 --- a/include/preview/__ranges/views/take.h +++ b/include/preview/__ranges/views/take.h @@ -10,6 +10,7 @@ #include #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" @@ -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 +#endif +#if PREVIEW_CXX_VERSION >= 20 +#include +#endif + namespace preview { namespace ranges { namespace views { @@ -54,21 +63,27 @@ struct take_niebloid { return ((void)count, preview_decay_copy(std::forward(r))); } - template - struct is_span : std::false_type {}; - template - struct is_span> : std::true_type {}; - - template::value /* true */> - struct return_category_span : std::true_type { - using category = return_category<2, span>; - }; template - struct return_category_span : std::false_type { + struct return_category_span : std::false_type { using category = return_category<0>; }; - - template::value /* true */> + template + struct return_category_span, D> : std::true_type { + using category = return_category<2, span>; + }; +#if PREVIEW_CXX_VERSION >= 20 + template + struct return_category_span, D> : std::true_type { + using category = return_category<2, std::span>; + }; +#endif + + template +#if PREVIEW_CXX_VERSION >= 17 + , is_specialization +#endif + >::value /* true */> struct return_category_string_view : std::true_type { using category = return_category<2, T>; }; @@ -77,7 +92,7 @@ struct take_niebloid { using category = return_category<0>; }; - template::value /* true */> + template, random_access_range, sized_range>::value /* true */> struct return_category_subrange : std::true_type { using category = return_category<2, subrange>>; }; @@ -103,8 +118,8 @@ struct take_niebloid { struct return_category_iota_view : std::false_type { using category = return_category<0>; }; - template - constexpr IV operator()(R&& e, ranges::range_difference_t f, return_category<3, IV>) const { + template + constexpr auto operator()(R&& e, ranges::range_difference_t f, return_category<3, T /* unused */>) const { using D = ranges::range_difference_t; return views::iota( *ranges::begin(e), @@ -138,21 +153,15 @@ struct take_niebloid { template using category = - std::conditional_t< - return_category_empty_view::value, typename return_category_empty_view::category, // 1 - std::conditional_t< - return_category_span::value, typename return_category_span::category, // 2 - std::conditional_t< - return_category_string_view::value, typename return_category_string_view::category, // 2 - std::conditional_t< - return_category_subrange::value, typename return_category_subrange::category, // 2 - std::conditional_t< - return_category_iota_view::value, typename return_category_iota_view::category, // 3 - std::conditional_t< - return_category_repeat_view::value, typename return_category_repeat_view::category, // 4 - return_category<5, take_view>>> // 5 - >>>>>; - + conditional_t< + return_category_empty_view, typename return_category_empty_view::category, // 1 + return_category_span, typename return_category_span::category, // 2 + return_category_string_view, typename return_category_string_view::category, // 2 + return_category_subrange, typename return_category_subrange::category, // 2 + return_category_iota_view, typename return_category_iota_view::category, // 3 + return_category_repeat_view, typename return_category_repeat_view::category, // 4 + return_category<5, take_view>> // 5 + >; public: template::value, int> = 0> diff --git a/test/ranges_views.cc b/test/ranges_views.cc index 036fb30..de4f714 100644 --- a/test/ranges_views.cc +++ b/test/ranges_views.cc @@ -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" @@ -414,3 +415,111 @@ TEST(VERSIONED(RangesViews), transform_view) { EXPECT_TRUE(ranges::equal(out | views::transform(rot13), "cppreference.com\n"s)); #endif } + +template +struct my_bind_front { + template + my_bind_front(F f, T&&... args) + : f_(std::move(f)) + , front_(std::forward_as_tuple(std::forward(args)...)) {} + + template + decltype(auto) operator()(Args&&... args) { + return call(preview::tuple_index_sequence{}, std::forward(args)...); + } + + template + decltype(auto) call(std::index_sequence, Args&&... args) { + return f_(std::get(front_)..., std::forward(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); + EXPECT_TRUE_TYPE(ranges::random_access_range); + EXPECT_TRUE_TYPE(std::is_same); + } + { // begin 2 + { + std::forward_list 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); + EXPECT_FALSE_TYPE(ranges::random_access_range); + EXPECT_TRUE_TYPE(std::is_same< + decltype(iter), + preview::counted_iterator::iterator> + >); + } + } + + { // end + const auto list1 = {3, 1, 4, 1, 5}; + const auto seq1 = list1 | views::take(4); + + EXPECT_TRUE_TYPE(ranges::sized_range); + EXPECT_TRUE_TYPE(ranges::random_access_range); + EXPECT_TRUE_TYPE(std::is_same); + + for (auto it = seq1.begin(); it != seq1.end(); ++it) { (void)*it; } + EXPECT_TRUE(ranges::equal(seq1, {3, 1, 4, 1})); + + std::list list2 = {2, 7, 1, 8, 2}; + const auto seq2 = list2 | views::take(4); + EXPECT_TRUE_TYPE (ranges::sized_range); + EXPECT_FALSE_TYPE(ranges::random_access_range); + EXPECT_TRUE_TYPE (std::is_same); + + 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"); +}