diff --git a/libcxx/include/__ranges/take_view.h b/libcxx/include/__ranges/take_view.h --- a/libcxx/include/__ranges/take_view.h +++ b/libcxx/include/__ranges/take_view.h @@ -226,6 +226,7 @@ }; template + requires requires{typename subrange<_Iter>;} struct __passthrough_type> { using type = subrange<_Iter>; }; diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp @@ -20,13 +20,14 @@ #include "test_iterators.h" template -concept CanBePiped = requires (View&& view, T&& t) { - { std::forward(view) | std::forward(t) }; -}; +concept CanBePiped = + requires(View&& view, T&& t) { + { std::forward(view) | std::forward(t) }; + }; struct SizedView : std::ranges::view_base { int* begin_ = nullptr; - int* end_ = nullptr; + int* end_ = nullptr; constexpr SizedView(int* begin, int* end) : begin_(begin), end_(end) {} constexpr auto begin() const { return forward_iterator(begin_); } @@ -39,7 +40,7 @@ template constexpr void test_small_range(const T& input) { constexpr int N = 100; - auto size = std::ranges::size(input); + auto size = std::ranges::size(input); auto result = input | std::views::take(N); assert(size < N); @@ -48,7 +49,7 @@ constexpr bool test() { constexpr int N = 8; - int buf[N] = {1, 2, 3, 4, 5, 6, 7, 8}; + int buf[N] = {1, 2, 3, 4, 5, 6, 7, 8}; // Test that `std::views::take` is a range adaptor. { @@ -66,7 +67,7 @@ // Test `adaptor | views::take` { SomeView view(buf, buf + N); - auto f = [](int i) { return i; }; + auto f = [](int i) { return i; }; auto const partial = std::views::transform(f) | std::views::take(3); using Result = std::ranges::take_view>; @@ -79,7 +80,7 @@ // Test `views::take | adaptor` { SomeView view(buf, buf + N); - auto f = [](int i) { return i; }; + auto f = [](int i) { return i; }; auto const partial = std::views::take(3) | std::views::transform(f); using Result = std::ranges::transform_view, decltype(f)>; @@ -91,25 +92,23 @@ // Check SFINAE friendliness { - struct NotAView { }; + struct NotAView {}; static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); - static_assert( CanBePiped); - static_assert( CanBePiped); + static_assert(CanBePiped); + static_assert(CanBePiped); static_assert(!CanBePiped); - static_assert(!CanBePiped); + static_assert(!CanBePiped); - static_assert(!CanBePiped); + static_assert(!CanBePiped); } } - { - static_assert(std::same_as); - } + { static_assert(std::same_as); } // `views::take(empty_view, n)` returns an `empty_view`. { - using Result = std::ranges::empty_view; + using Result = std::ranges::empty_view; [[maybe_unused]] std::same_as decltype(auto) result = std::views::empty | std::views::take(3); } @@ -128,73 +127,84 @@ } // `views::take(string_view, n)` returns a `string_view`. - { - { - std::string_view sv = "abcdef"; - std::same_as decltype(auto) result = sv | std::views::take(3); - assert(result.size() == 3); - } + {{std::string_view sv = "abcdef"; + std::same_as decltype(auto) result = sv | std::views::take(3); + assert(result.size() == 3); +} - { - std::u32string_view sv = U"abcdef"; - std::same_as decltype(auto) result = sv | std::views::take(3); - assert(result.size() == 3); - } - } +{ + std::u32string_view sv = U"abcdef"; + std::same_as decltype(auto) result = sv | std::views::take(3); + assert(result.size() == 3); +} +} - // `views::take(subrange, n)` returns a `subrange`. - { - auto subrange = std::ranges::subrange(buf, buf + N); - using Result = std::ranges::subrange; - std::same_as decltype(auto) result = subrange | std::views::take(3); - assert(result.size() == 3); - } +// `views::take(subrange, n)` returns a `subrange`. +{ + auto subrange = std::ranges::subrange(buf, buf + N); + using Result = std::ranges::subrange; + std::same_as decltype(auto) result = subrange | std::views::take(3); + assert(result.size() == 3); +} - // `views::take(subrange, n)` doesn't return a `subrange` if it's not a random access range. - { - SizedView v(buf, buf + N); - auto subrange = std::ranges::subrange(v.begin(), v.end()); +// `views::take(subrange, n)` doesn't return a `subrange` if it's not a random access range. +{ + SizedView v(buf, buf + N); + auto subrange = std::ranges::subrange(v.begin(), v.end()); - using Result = std::ranges::take_view, - sized_sentinel>>>; - std::same_as decltype(auto) result = subrange | std::views::take(3); - assert(result.size() == 3); - } + using Result = + std::ranges::take_view, sized_sentinel>>>; + std::same_as decltype(auto) result = subrange | std::views::take(3); + assert(result.size() == 3); +} - // `views::take(subrange, n)` returns a `subrange` with all default template arguments. - { - std::ranges::subrange, std::ranges::subrange_kind::sized> subrange; +// `views::take(subrange, n)` returns a `subrange` with all default template arguments. +{ + std::ranges::subrange, std::ranges::subrange_kind::sized> subrange; - using Result = std::ranges::subrange; - [[maybe_unused]] std::same_as decltype(auto) result = subrange | std::views::take(3); - } + using Result = std::ranges::subrange; + [[maybe_unused]] std::same_as decltype(auto) result = subrange | std::views::take(3); +} - // `views::take(iota_view, n)` returns an `iota_view`. - { - auto iota = std::views::iota(1, 8); - // The second template argument of the resulting `iota_view` is different because it has to be able to hold - // the `range_difference_t` of the input `iota_view`. - using Result = std::ranges::iota_view>; - std::same_as decltype(auto) result = iota | std::views::take(3); - assert(result.size() == 3); - } +// `views::take(iota_view, n)` returns an `iota_view`. +{ + auto iota = std::views::iota(1, 8); + // The second template argument of the resulting `iota_view` is different because it has to be able to hold + // the `range_difference_t` of the input `iota_view`. + using Result = std::ranges::iota_view>; + std::same_as decltype(auto) result = iota | std::views::take(3); + assert(result.size() == 3); +} - // When the size of the input range `s` is shorter than `n`, only `s` elements are taken. - { - test_small_range(std::span(buf)); - test_small_range(std::string_view("abcdef")); - test_small_range(std::ranges::subrange(buf, buf + N)); - test_small_range(std::views::iota(1, 8)); - } +// When the size of the input range `s` is shorter than `n`, only `s` elements are taken. +{ + test_small_range(std::span(buf)); + test_small_range(std::string_view("abcdef")); + test_small_range(std::ranges::subrange(buf, buf + N)); + test_small_range(std::views::iota(1, 8)); +} - // Test that it's possible to call `std::views::take` with any single argument as long as the resulting closure is - // never invoked. There is no good use case for it, but it's valid. - { - struct X { }; - [[maybe_unused]] auto partial = std::views::take(X{}); - } +// Test that it's possible to call `std::views::take` with any single argument as long as the resulting closure is +// never invoked. There is no good use case for it, but it's valid. +{ + struct X {}; + [[maybe_unused]] auto partial = std::views::take(X{}); +} + +// Test when `subrange` is not well formed +{ + int input[] = {1, 2, 3}; + using Iter = cpp20_input_iterator; + using Sent = sentinel_wrapper; + std::ranges::subrange r{Iter{input}, Sent{Iter{input + 3}}}; + [[maybe_unused]] auto tv = std::views::take(std::move(r), 1); + auto it = tv.begin(); + assert(*it == 1); + ++it; + assert(it == tv.end()); +} - return true; +return true; } int main(int, char**) {