[libc++][ranges]implement `std::views::take_while`

Differential Revision: https://reviews.llvm.org/D134952
This commit is contained in:
Hui Xie 2022-09-30 13:06:36 +01:00
parent b72a364bb5
commit a2c6a1193f
22 changed files with 1443 additions and 4 deletions

View File

@ -108,7 +108,7 @@
"`P0784R7 <https://wg21.link/P0784R7>`__","CWG","More constexpr containers","Cologne","|Complete|","12.0"
"`P0980R1 <https://wg21.link/P0980R1>`__","LWG","Making std::string constexpr","Cologne","|Complete|","15.0"
"`P1004R2 <https://wg21.link/P1004R2>`__","LWG","Making std::vector constexpr","Cologne","|Complete|","15.0"
"`P1035R7 <https://wg21.link/P1035R7>`__","LWG","Input Range Adaptors","Cologne","|In Progress|",""
"`P1035R7 <https://wg21.link/P1035R7>`__","LWG","Input Range Adaptors, Todo: elements_view and drop_while_view","Cologne","|In Progress|",""
"`P1065R2 <https://wg21.link/P1065R2>`__","LWG","Constexpr INVOKE","Cologne","|Complete|","12.0"
"`P1135R6 <https://wg21.link/P1135R6>`__","LWG","The C++20 Synchronization Library","Cologne","|Complete|","11.0"
"`P1207R4 <https://wg21.link/P1207R4>`__","LWG","Movability of Single-pass Iterators","Cologne","|Complete|","15.0"

1 Paper # Group Paper Name Meeting Status First released version
108 `P0784R7 <https://wg21.link/P0784R7>`__ CWG More constexpr containers Cologne |Complete| 12.0
109 `P0980R1 <https://wg21.link/P0980R1>`__ LWG Making std::string constexpr Cologne |Complete| 15.0
110 `P1004R2 <https://wg21.link/P1004R2>`__ LWG Making std::vector constexpr Cologne |Complete| 15.0
111 `P1035R7 <https://wg21.link/P1035R7>`__ LWG Input Range Adaptors Input Range Adaptors, Todo: elements_view and drop_while_view Cologne |In Progress|
112 `P1065R2 <https://wg21.link/P1065R2>`__ LWG Constexpr INVOKE Cologne |Complete| 12.0
113 `P1135R6 <https://wg21.link/P1135R6>`__ LWG The C++20 Synchronization Library Cologne |Complete| 11.0
114 `P1207R4 <https://wg21.link/P1207R4>`__ LWG Movability of Single-pass Iterators Cologne |Complete| 15.0

View File

@ -9,7 +9,7 @@
"`3435 <https://wg21.link/LWG3435>`__","``three_way_comparable_with<reverse_iterator<int*>, reverse_iterator<const int*>>``","November 2020","|Complete|","13.0"
"`3432 <https://wg21.link/LWG3432>`__","Missing requirement for ``comparison_category``","November 2020","|Complete|","16.0","|spaceship|"
"`3447 <https://wg21.link/LWG3447>`__","Deduction guides for ``take_view`` and ``drop_view`` have different constraints","November 2020","|Complete|","14.0"
"`3450 <https://wg21.link/LWG3450>`__","The const overloads of ``take_while_view::begin/end`` are underconstrained","November 2020","","","|ranges|"
"`3450 <https://wg21.link/LWG3450>`__","The const overloads of ``take_while_view::begin/end`` are underconstrained","November 2020","|Complete|","16.0","|ranges|"
"`3464 <https://wg21.link/LWG3464>`__","``istream::gcount()`` can overflow","November 2020","",""
"`2731 <https://wg21.link/LWG2731>`__","Existence of ``lock_guard<MutexTypes...>::mutex_type`` typedef unclear","November 2020","|Complete|","5.0"
"`2743 <https://wg21.link/LWG2743>`__","P0083R3 ``node_handle`` private members missing ""exposition only"" comment","November 2020","|Nothing To Do|",""
@ -34,7 +34,7 @@
"`3437 <https://wg21.link/LWG3437>`__","``__cpp_lib_polymorphic_allocator`` is in the wrong header","November 2020","|Complete|","14.0"
"`3446 <https://wg21.link/LWG3446>`__","``indirectly_readable_traits`` ambiguity for types with both ``value_type`` and ``element_type``","November 2020","|Complete|","14.0","|ranges|"
"`3448 <https://wg21.link/LWG3448>`__","``transform_view``'s ``sentinel<false>`` not comparable with ``iterator<true>``","November 2020","","","|ranges|"
"`3449 <https://wg21.link/LWG3449>`__","``take_view`` and ``take_while_view``'s ``sentinel<false>`` not comparable with their ``const iterator``","November 2020","","","|ranges|"
"`3449 <https://wg21.link/LWG3449>`__","``take_view`` and ``take_while_view``'s ``sentinel<false>`` not comparable with their ``const iterator``","November 2020","Complete","16.0","|ranges|"
"`3453 <https://wg21.link/LWG3453>`__","Generic code cannot call ``ranges::advance(i, s)``","November 2020","|Nothing To Do|","","|ranges|"
"`3455 <https://wg21.link/LWG3455>`__","Incorrect Postconditions on ``unique_ptr`` move assignment","November 2020","|Nothing To Do|",""
"`3460 <https://wg21.link/LWG3460>`__","Unimplementable ``noop_coroutine_handle`` guarantees","November 2020","|Complete|","14.0"
@ -175,7 +175,7 @@
"`3704 <https://wg21.link/LWG3704>`__","LWG 2059 added overloads that might be ill-formed for sets","July 2022","",""
"`3705 <https://wg21.link/LWG3705>`__","Hashability shouldn't depend on basic_string's allocator","July 2022","|Complete|","16.0"
"`3707 <https://wg21.link/LWG3707>`__","chunk_view::outer-iterator::value_type::size should return unsigned type","July 2022","","","|ranges|"
"`3708 <https://wg21.link/LWG3708>`__","``take_while_view::sentinel``'s conversion constructor should move","July 2022","","","|ranges|"
"`3708 <https://wg21.link/LWG3708>`__","``take_while_view::sentinel``'s conversion constructor should move","July 2022","Complete","16.0","|ranges|"
"`3709 <https://wg21.link/LWG3709>`__","LWG-3703 was underly ambitious","July 2022","",""
"`3710 <https://wg21.link/LWG3710>`__","The ``end`` of ``chunk_view`` for input ranges can be ``const``","July 2022","","","|ranges|"
"`3711 <https://wg21.link/LWG3711>`__","Missing preconditions for slide_view constructor","July 2022","","","|ranges|"

Can't render this file because it has a wrong number of fields in line 2.

View File

@ -495,6 +495,7 @@ set(files
__ranges/size.h
__ranges/subrange.h
__ranges/take_view.h
__ranges/take_while_view.h
__ranges/transform_view.h
__ranges/view_interface.h
__ranges/views.h

View File

@ -0,0 +1,177 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP___RANGES_TAKE_WHILE_VIEW_H
#define _LIBCPP___RANGES_TAKE_WHILE_VIEW_H
#include <__concepts/constructible.h>
#include <__concepts/convertible_to.h>
#include <__config>
#include <__functional/bind_back.h>
#include <__functional/invoke.h>
#include <__iterator/concepts.h>
#include <__memory/addressof.h>
#include <__ranges/access.h>
#include <__ranges/all.h>
#include <__ranges/concepts.h>
#include <__ranges/copyable_box.h>
#include <__ranges/range_adaptor.h>
#include <__ranges/view_interface.h>
#include <__type_traits/decay.h>
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_object.h>
#include <__type_traits/maybe_const.h>
#include <__utility/forward.h>
#include <__utility/in_place.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 20
namespace ranges {
// The spec uses the unnamed requirement inside the `begin` and `end` member functions:
// constexpr auto begin() const
// requires range<const V> && indirect_unary_predicate<const Pred, iterator_t<const V>>
// However, due to a clang-14 and clang-15 bug, the above produces a hard error when `const V` is not a range.
// The workaround is to create a named concept and use the concept instead.
// As of take_while_view is implemented, the clang-trunk has already fixed the bug.
// It is OK to remove the workaround once our CI no longer uses clang-14, clang-15 based compilers,
// because we don't actually expect a lot of vendors to ship a new libc++ with an old clang.
template <class _View, class _Pred>
concept __take_while_const_is_range =
range<const _View> && indirect_unary_predicate<const _Pred, iterator_t<const _View>>;
template <view _View, class _Pred>
requires input_range<_View> && is_object_v<_Pred> && indirect_unary_predicate<const _Pred, iterator_t<_View>>
class take_while_view : public view_interface<take_while_view<_View, _Pred>> {
template <bool>
class __sentinel;
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
_LIBCPP_NO_UNIQUE_ADDRESS __copyable_box<_Pred> __pred_;
public:
_LIBCPP_HIDE_FROM_ABI take_while_view()
requires default_initializable<_View> && default_initializable<_Pred>
= default;
_LIBCPP_HIDE_FROM_ABI constexpr take_while_view(_View __base, _Pred __pred)
: __base_(std::move(__base)), __pred_(std::in_place, std::move(__pred)) {}
_LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
requires copy_constructible<_View>
{
return __base_;
}
_LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
_LIBCPP_HIDE_FROM_ABI constexpr const _Pred& pred() const { return *__pred_; }
_LIBCPP_HIDE_FROM_ABI constexpr auto begin()
requires(!__simple_view<_View>)
{
return ranges::begin(__base_);
}
_LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
requires __take_while_const_is_range<_View, _Pred>
{
return ranges::begin(__base_);
}
_LIBCPP_HIDE_FROM_ABI constexpr auto end()
requires(!__simple_view<_View>)
{
return __sentinel</*_Const=*/false>(ranges::end(__base_), std::addressof(*__pred_));
}
_LIBCPP_HIDE_FROM_ABI constexpr auto end() const
requires __take_while_const_is_range<_View, _Pred>
{
return __sentinel</*_Const=*/true>(ranges::end(__base_), std::addressof(*__pred_));
}
};
template <class _Range, class _Pred>
take_while_view(_Range&&, _Pred) -> take_while_view<views::all_t<_Range>, _Pred>;
template <view _View, class _Pred>
requires input_range<_View> && is_object_v<_Pred> && indirect_unary_predicate<const _Pred, iterator_t<_View>>
template <bool _Const>
class take_while_view<_View, _Pred>::__sentinel {
using _Base = __maybe_const<_Const, _View>;
sentinel_t<_Base> __end_ = sentinel_t<_Base>();
const _Pred* __pred_ = nullptr;
friend class __sentinel<!_Const>;
public:
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end, const _Pred* __pred)
: __end_(std::move(__end)), __pred_(__pred) {}
_LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __s)
requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
: __end_(std::move(__s.__end_)), __pred_(__s.__pred_) {}
_LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Base> base() const { return __end_; }
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const iterator_t<_Base>& __x, const __sentinel& __y) {
return __x == __y.__end_ || !std::invoke(*__y.__pred_, *__x);
}
template <bool _OtherConst = !_Const>
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool
operator==(const iterator_t<__maybe_const<_OtherConst, _View>>& __x, const __sentinel& __y) {
return __x == __y.__end_ || !std::invoke(*__y.__pred_, *__x);
}
};
namespace views {
namespace __take_while {
struct __fn {
template <class _Range, class _Pred>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Pred&& __pred) const
noexcept(noexcept(/**/ take_while_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred))))
-> decltype(/*--*/ take_while_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred))) {
return /*-------------*/ take_while_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred));
}
template <class _Pred>
requires constructible_from<decay_t<_Pred>, _Pred>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Pred&& __pred) const
noexcept(is_nothrow_constructible_v<decay_t<_Pred>, _Pred>) {
return __range_adaptor_closure_t(std::__bind_back(*this, std::forward<_Pred>(__pred)));
}
};
} // namespace __take_while
inline namespace __cpo {
inline constexpr auto take_while = __take_while::__fn{};
} // namespace __cpo
} // namespace views
} // namespace ranges
#endif // _LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___RANGES_TAKE_WHILE_VIEW_H

View File

@ -1031,6 +1031,7 @@ module std [system] {
module size { private header "__ranges/size.h" }
module subrange { private header "__ranges/subrange.h" }
module take_view { private header "__ranges/take_view.h" }
module take_while_view { private header "__ranges/take_while_view.h" }
module transform_view {
private header "__ranges/transform_view.h"
export functional.__functional.bind_back

View File

@ -198,6 +198,14 @@ namespace std::ranges {
template<class T>
inline constexpr bool enable_borrowed_range<take_view<T>> = enable_borrowed_range<T>;
// [range.take.while], take while view
template<view V, class Pred>
requires input_range<V> && is_object_v<Pred> &&
indirect_unary_predicate<const Pred, iterator_t<V>>
class take_while_view;
namespace views { inline constexpr unspecified take_while = unspecified; }
template<copy_constructible T>
requires is_object_v<T>
class single_view;
@ -311,6 +319,7 @@ namespace std {
#include <__ranges/size.h>
#include <__ranges/subrange.h>
#include <__ranges/take_view.h>
#include <__ranges/take_while_view.h>
#include <__ranges/transform_view.h>
#include <__ranges/view_interface.h>
#include <__ranges/views.h>

View File

@ -526,6 +526,7 @@ END-SCRIPT
#include <__ranges/size.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/size.h'}}
#include <__ranges/subrange.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/subrange.h'}}
#include <__ranges/take_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/take_view.h'}}
#include <__ranges/take_while_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/take_while_view.h'}}
#include <__ranges/transform_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/transform_view.h'}}
#include <__ranges/view_interface.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/view_interface.h'}}
#include <__ranges/views.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/views.h'}}

View File

@ -0,0 +1,117 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// std::views::take_while
#include <algorithm>
#include <cassert>
#include <ranges>
#include <type_traits>
#include <utility>
#include "types.h"
struct Pred {
constexpr bool operator()(int i) const { return i < 3; }
};
struct Foo {};
struct MoveOnlyView : IntBufferViewBase {
using IntBufferViewBase::IntBufferViewBase;
MoveOnlyView(const MoveOnlyView&) = delete;
MoveOnlyView& operator=(const MoveOnlyView&) = delete;
MoveOnlyView(MoveOnlyView&&) = default;
MoveOnlyView& operator=(MoveOnlyView&&) = default;
constexpr const int* begin() const { return buffer_; }
constexpr const int* end() const { return buffer_ + size_; }
};
static_assert(!std::is_invocable_v<decltype((std::views::take_while))>);
static_assert(std::is_invocable_v<decltype((std::views::take_while)), int>);
static_assert(std::is_invocable_v<decltype((std::views::take_while)), Pred>);
static_assert(!std::is_invocable_v<decltype((std::views::take_while)), int, Pred>);
static_assert(std::is_invocable_v<decltype((std::views::take_while)), int (&)[2], Pred>);
static_assert(!std::is_invocable_v<decltype((std::views::take_while)), Foo (&)[2], Pred>);
static_assert(std::is_invocable_v<decltype((std::views::take_while)), MoveOnlyView, Pred>);
template <class View, class T>
concept CanBePiped =
requires(View&& view, T&& t) {
{ std::forward<View>(view) | std::forward<T>(t) };
};
static_assert(!CanBePiped<MoveOnlyView, decltype(std::views::take_while)>);
static_assert(CanBePiped<MoveOnlyView, decltype(std::views::take_while(Pred{}))>);
static_assert(!CanBePiped<int, decltype(std::views::take_while(Pred{}))>);
static_assert(CanBePiped<int (&)[2], decltype(std::views::take_while(Pred{}))>);
static_assert(!CanBePiped<Foo (&)[2], decltype(std::views::take_while(Pred{}))>);
constexpr bool test() {
int buff[] = {1, 2, 3, 4, 3, 2, 1};
// Test `views::take_while(p)(v)`
{
using Result = std::ranges::take_while_view<MoveOnlyView, Pred>;
std::same_as<Result> decltype(auto) result = std::views::take_while(Pred{})(MoveOnlyView{buff});
auto expected = {1, 2};
assert(std::ranges::equal(result, expected));
}
{
auto const partial = std::views::take_while(Pred{});
using Result = std::ranges::take_while_view<MoveOnlyView, Pred>;
std::same_as<Result> decltype(auto) result = partial(MoveOnlyView{buff});
auto expected = {1, 2};
assert(std::ranges::equal(result, expected));
}
// Test `v | views::take_while(p)`
{
using Result = std::ranges::take_while_view<MoveOnlyView, Pred>;
std::same_as<Result> decltype(auto) result = MoveOnlyView{buff} | std::views::take_while(Pred{});
auto expected = {1, 2};
assert(std::ranges::equal(result, expected));
}
{
auto const partial = std::views::take_while(Pred{});
using Result = std::ranges::take_while_view<MoveOnlyView, Pred>;
std::same_as<Result> decltype(auto) result = MoveOnlyView{buff} | partial;
auto expected = {1, 2};
assert(std::ranges::equal(result, expected));
}
// Test `views::take_while(v, p)`
{
using Result = std::ranges::take_while_view<MoveOnlyView, Pred>;
std::same_as<Result> decltype(auto) result = std::views::take_while(MoveOnlyView{buff}, Pred{});
auto expected = {1, 2};
assert(std::ranges::equal(result, expected));
}
// Test adaptor | adaptor
{
struct Pred2 {
constexpr bool operator()(int i) const { return i < 2; }
};
auto const partial = std::views::take_while(Pred{}) | std::views::take_while(Pred2{});
using Result = std::ranges::take_while_view<std::ranges::take_while_view<MoveOnlyView, Pred>, Pred2>;
std::same_as<Result> decltype(auto) result = MoveOnlyView{buff} | partial;
auto expected = {1};
assert(std::ranges::equal(result, expected));
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,87 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// constexpr V base() const & requires copy_constructible<V> { return base_; }
// constexpr V base() && { return std::move(base_); }
#include <cassert>
#include <ranges>
#include <type_traits>
#include <utility>
#include "MoveOnly.h"
#include "types.h"
struct View : std::ranges::view_interface<View> {
int i;
int* begin() const;
int* end() const;
};
struct MoveOnlyView : View {
MoveOnly mo;
};
template <class T>
concept HasBase = requires(T&& t) { std::forward<T>(t).base(); };
struct Pred {
constexpr bool operator()(int i) const { return i > 5; }
};
static_assert(HasBase<std::ranges::take_while_view<View, Pred> const&>);
static_assert(HasBase<std::ranges::take_while_view<View, Pred>&&>);
static_assert(!HasBase<std::ranges::take_while_view<MoveOnlyView, Pred> const&>);
static_assert(HasBase<std::ranges::take_while_view<MoveOnlyView, Pred>&&>);
constexpr bool test() {
// const &
{
const std::ranges::take_while_view<View, Pred> twv{View{{}, 5}, {}};
std::same_as<View> decltype(auto) v = twv.base();
assert(v.i == 5);
}
// &
{
std::ranges::take_while_view<View, Pred> twv{View{{}, 5}, {}};
std::same_as<View> decltype(auto) v = twv.base();
assert(v.i == 5);
}
// &&
{
std::ranges::take_while_view<View, Pred> twv{View{{}, 5}, {}};
std::same_as<View> decltype(auto) v = std::move(twv).base();
assert(v.i == 5);
}
// const &&
{
const std::ranges::take_while_view<View, Pred> twv{View{{}, 5}, {}};
std::same_as<View> decltype(auto) v = std::move(twv).base();
assert(v.i == 5);
}
// move only
{
std::ranges::take_while_view<MoveOnlyView, Pred> twv{MoveOnlyView{{}, 5}, {}};
std::same_as<MoveOnlyView> decltype(auto) v = std::move(twv).base();
assert(v.mo.get() == 5);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,108 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// constexpr auto begin() requires (!simple-view<V>)
// { return ranges::begin(base_); }
//
// constexpr auto begin() const
// requires range<const V> &&
// indirect_unary_predicate<const Pred, iterator_t<const V>>
// { return ranges::begin(base_); }
#include <cassert>
#include <ranges>
#include <type_traits>
#include <utility>
#include "types.h"
// Test Constraints
template <class T>
concept HasConstBegin = requires(const T& ct) { ct.begin(); };
template <class T>
concept HasBegin = requires(T& t) { t.begin(); };
template <class T>
concept HasConstAndNonConstBegin =
HasConstBegin<T> &&
requires(T& t, const T& ct) { requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>; };
template <class T>
concept HasOnlyNonConstBegin = HasBegin<T> && !HasConstBegin<T>;
template <class T>
concept HasOnlyConstBegin = HasConstBegin<T> && !HasConstAndNonConstBegin<T>;
struct Pred {
constexpr bool operator()(int i) const { return i > 5; }
};
static_assert(HasOnlyConstBegin<std::ranges::take_while_view<SimpleView, Pred>>);
static_assert(HasOnlyNonConstBegin<std::ranges::take_while_view<ConstNotRange, Pred>>);
static_assert(HasConstAndNonConstBegin<std::ranges::take_while_view<NonSimple, Pred>>);
struct NotPredForConst {
constexpr bool operator()(int& i) const { return i > 5; }
};
static_assert(HasOnlyNonConstBegin<std::ranges::take_while_view<NonSimple, NotPredForConst>>);
constexpr bool test() {
// simple-view
{
int buffer[] = {1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1};
SimpleView v{buffer};
std::ranges::take_while_view twv(v, Pred{});
std::same_as<int*> decltype(auto) it1 = twv.begin();
assert(it1 == buffer);
std::same_as<int*> decltype(auto) it2 = std::as_const(twv).begin();
assert(it2 == buffer);
}
// const not range
{
int buffer[] = {1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1};
ConstNotRange v{buffer};
std::ranges::take_while_view twv(v, Pred{});
std::same_as<int*> decltype(auto) it1 = twv.begin();
assert(it1 == buffer);
}
// NonSimple
{
int buffer[] = {1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1};
NonSimple v{buffer};
std::ranges::take_while_view twv(v, Pred{});
std::same_as<int*> decltype(auto) it1 = twv.begin();
assert(it1 == buffer);
std::same_as<const int*> decltype(auto) it2 = std::as_const(twv).begin();
assert(it2 == buffer);
}
// NotPredForConst
// LWG 3450: The const overloads of `take_while_view::begin/end` are underconstrained
{
int buffer[] = {1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1};
NonSimple v{buffer};
std::ranges::take_while_view twv(v, NotPredForConst{});
std::same_as<int*> decltype(auto) it1 = twv.begin();
assert(it1 == buffer);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// template<class R, class Pred>
// take_while_view(R&&, Pred) -> take_while_view<views::all_t<R>, Pred>;
#include <cassert>
#include <ranges>
#include <utility>
#include "types.h"
struct Container {
int* begin() const;
int* end() const;
};
struct View : std::ranges::view_base {
int* begin() const;
int* end() const;
};
struct Pred {
bool operator()(int i) const;
};
bool pred(int);
static_assert(std::is_same_v<decltype(std::ranges::take_while_view(Container{}, Pred{})),
std::ranges::take_while_view<std::ranges::owning_view<Container>, Pred>>);
static_assert(std::is_same_v<decltype(std::ranges::take_while_view(View{}, pred)), //
std::ranges::take_while_view<View, bool (*)(int)>>);
static_assert(std::is_same_v<decltype(std::ranges::take_while_view(View{}, Pred{})), //
std::ranges::take_while_view<View, Pred>>);
void testRef() {
Container c{};
Pred p{};
static_assert(std::is_same_v<decltype(std::ranges::take_while_view(c, p)),
std::ranges::take_while_view<std::ranges::ref_view<Container>, Pred>>);
}

View File

@ -0,0 +1,56 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// take_while_view() requires default_initializable<V> && default_initializable<Pred> = default;
#include <cassert>
#include <ranges>
#include <type_traits>
template <bool defaultInitable>
struct View : std::ranges::view_base {
int i;
constexpr explicit View()
requires defaultInitable
= default;
int* begin() const;
int* end() const;
};
template <bool defaultInitable>
struct Pred {
int i;
constexpr explicit Pred()
requires defaultInitable
= default;
bool operator()(int) const;
};
// clang-format off
static_assert( std::is_default_constructible_v<std::ranges::take_while_view<View<true >, Pred<true >>>);
static_assert(!std::is_default_constructible_v<std::ranges::take_while_view<View<false>, Pred<true >>>);
static_assert(!std::is_default_constructible_v<std::ranges::take_while_view<View<true >, Pred<false>>>);
static_assert(!std::is_default_constructible_v<std::ranges::take_while_view<View<false>, Pred<false>>>);
// clang-format on
constexpr bool test() {
{
std::ranges::take_while_view<View<true>, Pred<true>> twv = {};
assert(twv.base().i == 0);
assert(twv.pred().i == 0);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,49 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// constexpr take_while_view(V base, Pred pred);
#include <cassert>
#include <ranges>
#include <type_traits>
#include <utility>
#include "MoveOnly.h"
struct View : std::ranges::view_base {
MoveOnly mo;
int* begin() const;
int* end() const;
};
struct Pred {
bool copied = false;
bool moved = false;
constexpr Pred() = default;
constexpr Pred(Pred&&) : moved(true) {}
constexpr Pred(const Pred&) : copied(true) {}
bool operator()(int) const;
};
constexpr bool test() {
{
std::ranges::take_while_view<View, Pred> twv = {View{{}, MoveOnly{5}}, Pred{}};
assert(twv.pred().moved);
assert(!twv.pred().copied);
assert(std::move(twv).base().mo.get() == 5);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,110 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// constexpr auto end() requires (!simple-view<V>)
// { return sentinel<false>(ranges::end(base_), addressof(*pred_)); }
// constexpr auto end() const
// requires range<const V> &&
// indirect_unary_predicate<const Pred, iterator_t<const V>>
// { return sentinel<true>(ranges::end(base_), addressof(*pred_)); }
#include <cassert>
#include <ranges>
#include <type_traits>
#include <utility>
#include "types.h"
// Test Constraints
template <class T>
concept HasConstEnd = requires(const T& ct) { ct.end(); };
template <class T>
concept HasEnd = requires(T& t) { t.end(); };
template <class T>
concept HasConstAndNonConstEnd =
HasConstEnd<T> && requires(T& t, const T& ct) { requires !std::same_as<decltype(t.end()), decltype(ct.end())>; };
template <class T>
concept HasOnlyNonConstEnd = HasEnd<T> && !HasConstEnd<T>;
template <class T>
concept HasOnlyConstEnd = HasConstEnd<T> && !HasConstAndNonConstEnd<T>;
struct Pred {
constexpr bool operator()(int i) const { return i < 5; }
};
static_assert(HasOnlyConstEnd<std::ranges::take_while_view<SimpleView, Pred>>);
static_assert(HasOnlyNonConstEnd<std::ranges::take_while_view<ConstNotRange, Pred>>);
static_assert(HasConstAndNonConstEnd<std::ranges::take_while_view<NonSimple, Pred>>);
struct NotPredForConst {
constexpr bool operator()(int& i) const { return i > 5; }
};
static_assert(HasOnlyNonConstEnd<std::ranges::take_while_view<NonSimple, NotPredForConst>>);
constexpr bool test() {
// simple-view
{
int buffer[] = {1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1};
SimpleView v{buffer};
std::ranges::take_while_view twv(v, Pred{});
decltype(auto) it1 = twv.end();
assert(it1 == buffer + 4);
decltype(auto) it2 = std::as_const(twv).end();
assert(it2 == buffer + 4);
static_assert(std::same_as<decltype(it1), decltype(it2)>);
}
// const not range
{
int buffer[] = {1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1};
ConstNotRange v{buffer};
std::ranges::take_while_view twv(v, Pred{});
decltype(auto) it1 = twv.end();
assert(it1 == buffer + 4);
}
// NonSimple
{
int buffer[] = {1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1};
NonSimple v{buffer};
std::ranges::take_while_view twv(v, Pred{});
decltype(auto) it1 = twv.end();
assert(it1 == buffer + 4);
decltype(auto) it2 = std::as_const(twv).end();
assert(it2 == buffer + 4);
static_assert(!std::same_as<decltype(it1), decltype(it2)>);
}
// NotPredForConst
// LWG 3450: The const overloads of `take_while_view::begin/end` are underconstrained
{
int buffer[] = {1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1};
NonSimple v{buffer};
std::ranges::take_while_view twv(v, NotPredForConst{});
decltype(auto) it1 = twv.end();
assert(it1 == buffer);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// Some basic examples of how take_while_view might be used in the wild. This is a general
// collection of sample algorithms and functions that try to mock general usage of
// this view.
#include <algorithm>
#include <cassert>
#include <ranges>
int main(int, char**) {
{
auto input = {0, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1, 0};
auto small = [](const auto x) noexcept { return x < 5; };
auto small_ints = input | std::views::take_while(small);
auto expected = {0, 1, 2, 3, 4};
assert(std::ranges::equal(small_ints, expected));
}
return 0;
}

View File

@ -0,0 +1,68 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// constexpr const Pred& pred() const;
#include <cassert>
#include <ranges>
#include <type_traits>
#include <utility>
struct View : std::ranges::view_interface<View> {
int* begin() const;
int* end() const;
};
struct Pred {
int i;
bool operator()(int) const;
};
constexpr bool test() {
// &
{
std::ranges::take_while_view<View, Pred> twv{{}, Pred{5}};
decltype(auto) x = twv.pred();
static_assert(std::same_as<decltype(x), Pred const&>);
assert(x.i == 5);
}
// const &
{
const std::ranges::take_while_view<View, Pred> twv{{}, Pred{5}};
decltype(auto) x = twv.pred();
static_assert(std::same_as<decltype(x), Pred const&>);
assert(x.i == 5);
}
// &&
{
std::ranges::take_while_view<View, Pred> twv{{}, Pred{5}};
decltype(auto) x = std::move(twv).pred();
static_assert(std::same_as<decltype(x), Pred const&>);
assert(x.i == 5);
}
// const &&
{
const std::ranges::take_while_view<View, Pred> twv{{}, Pred{5}};
decltype(auto) x = std::move(twv).pred();
static_assert(std::same_as<decltype(x), Pred const&>);
assert(x.i == 5);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,47 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// concept checking
// template<view V, class Pred>
// requires input_range<V> && is_object_v<Pred> &&
// indirect_unary_predicate<const Pred, iterator_t<V>>
// class take_while_view;
#include <array>
#include <ranges>
#include "test_iterators.h"
template <class It>
using Range = std::ranges::subrange<It, sentinel_wrapper<It>>;
template <class Val = int>
struct Pred {
bool operator()(const Val&) const;
};
template <class V, class Pred>
concept HasTakeWhileView = requires { typename std::ranges::take_while_view<V, Pred>; };
static_assert(HasTakeWhileView<Range<int*>, bool (*)(int)>);
static_assert(HasTakeWhileView<Range<int*>, Pred<int>>);
// !view<V>
static_assert(!HasTakeWhileView<std::array<int, 5>, Pred<int>>);
// !input_range
static_assert(!HasTakeWhileView<Range<cpp20_output_iterator<int*>>, bool (*)(int)>);
// !is_object_v<Pred>
static_assert(!HasTakeWhileView<Range<int*>, Pred<int>&>);
// !indirect_unary_predicate<const Pred, iterator_t<V>>
static_assert(!HasTakeWhileView<Range<int*>, int>);
static_assert(!HasTakeWhileView<Range<int**>, Pred<int>>);

View File

@ -0,0 +1,86 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// constexpr explicit sentinel(sentinel_t<Base> end, const Pred* pred);
#include <cassert>
#include <ranges>
#include <utility>
#include "../types.h"
struct Sent {
int i;
friend constexpr bool operator==(int* iter, const Sent& s) { return s.i > *iter; }
};
struct Range : std::ranges::view_base {
int* begin() const;
Sent end();
};
struct Pred {
bool operator()(int i) const;
};
// Test explicit
template <class T>
void conversion_test(T);
template <class T, class... Args>
concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); };
static_assert(ImplicitlyConstructible<int, int>);
static_assert(std::is_constructible_v<std::ranges::sentinel_t<std::ranges::take_while_view<Range, Pred>>,
std::ranges::sentinel_t<Range>,
const Pred*>);
static_assert(!ImplicitlyConstructible<std::ranges::sentinel_t<std::ranges::take_while_view<Range, Pred>>,
std::ranges::sentinel_t<Range>,
const Pred*>);
constexpr bool test() {
// base is init correctly
{
using R = std::ranges::take_while_view<Range, bool (*)(int)>;
using Sentinel = std::ranges::sentinel_t<R>;
Sentinel s1(Sent{5}, nullptr);
assert(s1.base().i == 5);
}
// pred is init correctly
{
bool called = false;
auto pred = [&](int) {
called = true;
return false;
};
using R = std::ranges::take_while_view<Range, decltype(pred)>;
using Sentinel = std::ranges::sentinel_t<R>;
int i = 10;
int* iter = &i;
Sentinel s(Sent{0}, &pred);
bool b = iter == s;
assert(called);
assert(b);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,138 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// constexpr sentinel(sentinel<!Const> s)
// requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;
#include <cassert>
#include <ranges>
#include "../types.h"
struct Sent {
int i;
constexpr Sent() = default;
constexpr Sent(int ii) : i(ii) {}
friend constexpr bool operator==(int* iter, const Sent& s) { return s.i > *iter; }
};
struct ConstSent {
int i;
constexpr ConstSent() = default;
constexpr ConstSent(int ii) : i(ii) {}
constexpr ConstSent(const Sent& s) : i(s.i) {}
friend constexpr bool operator==(int* iter, const ConstSent& s) { return s.i > *iter; }
};
struct Range : std::ranges::view_base {
int* begin() const;
Sent end();
ConstSent end() const;
};
struct Pred {
bool operator()(int i) const;
};
struct NonConvertConstSent {
int i;
constexpr NonConvertConstSent() = default;
constexpr NonConvertConstSent(int ii) : i(ii) {}
friend constexpr bool operator==(int* iter, const NonConvertConstSent& s) { return s.i > *iter; }
};
struct NonConvertConstSentRange : std::ranges::view_base {
int* begin() const;
Sent end();
NonConvertConstSent end() const;
};
// Test Constraint
static_assert(std::is_constructible_v<std::ranges::sentinel_t<const std::ranges::take_while_view<Range, Pred>>,
std::ranges::sentinel_t<std::ranges::take_while_view<Range, Pred>>>);
// !Const
static_assert(!std::is_constructible_v<std::ranges::sentinel_t<std::ranges::take_while_view<Range, Pred>>,
std::ranges::sentinel_t<const std::ranges::take_while_view<Range, Pred>>>);
// !convertible_to<sentinel_t<V>, sentinel_t<Base>>
static_assert(!std::is_constructible_v<
std::ranges::sentinel_t<const std::ranges::take_while_view<NonConvertConstSentRange, Pred>>,
std::ranges::sentinel_t<std::ranges::take_while_view<NonConvertConstSentRange, Pred>>>);
constexpr bool test() {
// base is init correctly
{
using R = std::ranges::take_while_view<Range, bool (*)(int)>;
using Sentinel = std::ranges::sentinel_t<R>;
using ConstSentinel = std::ranges::sentinel_t<const R>;
static_assert(!std::same_as<Sentinel, ConstSentinel>);
Sentinel s1(Sent{5}, nullptr);
ConstSentinel s2 = s1;
assert(s2.base().i == 5);
}
// pred is init correctly
{
bool called = false;
auto pred = [&](int) {
called = true;
return false;
};
using R = std::ranges::take_while_view<Range, decltype(pred)>;
using Sentinel = std::ranges::sentinel_t<R>;
using ConstSentinel = std::ranges::sentinel_t<const R>;
static_assert(!std::same_as<Sentinel, ConstSentinel>);
int i = 10;
int* iter = &i;
Sentinel s1(Sent{0}, &pred);
ConstSentinel s2 = s1;
[[maybe_unused]] bool b = iter == s2;
assert(called);
}
// LWG 3708 `take_while_view::sentinel`'s conversion constructor should move
{
struct MoveOnlyConvert {
int i;
constexpr MoveOnlyConvert() = default;
constexpr MoveOnlyConvert(Sent&& s) : i(s.i) { s.i = 0; }
constexpr bool operator==(int* iter) const { return i > *iter; }
};
struct Rng : std::ranges::view_base {
int* begin() const;
Sent end();
MoveOnlyConvert end() const;
};
using R = std::ranges::take_while_view<Rng, Pred>;
using Sentinel = std::ranges::sentinel_t<R>;
using ConstSentinel = std::ranges::sentinel_t<const R>;
static_assert(!std::same_as<Sentinel, ConstSentinel>);
Sentinel s1(Sent{5}, nullptr);
ConstSentinel s2 = s1;
assert(s2.base().i == 5);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// sentinel() = default;
#include <cassert>
#include <ranges>
struct Sent {
bool b; // deliberately uninitialised
friend constexpr bool operator==(int*, const Sent& s) { return s.b; }
};
struct Range : std::ranges::view_base {
int* begin() const;
Sent end();
};
constexpr bool test() {
{
using R = std::ranges::take_while_view<Range, bool (*)(int)>;
using Sentinel = std::ranges::sentinel_t<R>;
Sentinel s1 = {};
assert(!s1.base().b);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,204 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// friend constexpr bool operator==(const iterator_t<Base>& x, const sentinel& y);
//
// template<bool OtherConst = !Const>
// requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
// friend constexpr bool operator==(const iterator_t<maybe-const<OtherConst, V>>& x,
// const sentinel& y);
#include <array>
#include <cassert>
#include <ranges>
#include "../types.h"
template <bool Const>
struct Iter {
int* it_;
using value_type = int;
using difference_type = intptr_t;
using iterator_concept = std::input_iterator_tag;
constexpr decltype(auto) operator*() const { return *it_; }
constexpr Iter& operator++() {
++it_;
return *this;
}
constexpr void operator++(int) { ++it_; }
};
template <bool Const>
struct Sent {
int* end_;
constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; }
};
template <bool Const>
struct CrossComparableSent {
int* end_;
template <bool C>
constexpr bool operator==(const Iter<C>& i) const {
return i.it_ == end_;
}
};
template <template <bool> typename St>
struct Range : IntBufferViewBase {
using IntBufferViewBase::IntBufferViewBase;
constexpr Iter<false> begin() { return Iter<false>{buffer_}; }
constexpr Iter<true> begin() const { return Iter<true>{buffer_}; }
constexpr St<false> end() { return St<false>{buffer_ + size_}; }
constexpr St<true> end() const { return St<true>{buffer_ + size_}; }
};
using R = Range<Sent>;
using CrossComparableR = Range<CrossComparableSent>;
struct LessThan3 {
constexpr bool operator()(int i) const { return i < 3; }
};
// Test Constraint
template <class I, class S>
concept HasEqual = requires(const I i, const S s) { i == s; };
using std::ranges::iterator_t;
using std::ranges::sentinel_t;
using std::ranges::take_while_view;
static_assert(HasEqual<iterator_t<take_while_view<R, LessThan3>>, //
sentinel_t<take_while_view<R, LessThan3>>>);
static_assert(!HasEqual<iterator_t<const take_while_view<R, LessThan3>>, //
sentinel_t<take_while_view<R, LessThan3>>>);
static_assert(!HasEqual<iterator_t<take_while_view<R, LessThan3>>, //
sentinel_t<const take_while_view<R, LessThan3>>>);
static_assert(HasEqual<iterator_t<const take_while_view<R, LessThan3>>, //
sentinel_t<const take_while_view<R, LessThan3>>>);
static_assert(HasEqual<iterator_t<take_while_view<R, LessThan3>>, //
sentinel_t<take_while_view<R, LessThan3>>>);
static_assert(HasEqual<iterator_t<const take_while_view<CrossComparableR, LessThan3>>, //
sentinel_t<take_while_view<CrossComparableR, LessThan3>>>);
static_assert(HasEqual<iterator_t<take_while_view<CrossComparableR, LessThan3>>, //
sentinel_t<const take_while_view<CrossComparableR, LessThan3>>>);
static_assert(HasEqual<iterator_t<const take_while_view<CrossComparableR, LessThan3>>, //
sentinel_t<const take_while_view<CrossComparableR, LessThan3>>>);
template <class R, bool ConstIter, bool ConstSent>
constexpr void testOne() {
auto getBegin = [](auto&& rng) {
if constexpr (ConstIter) {
return std::as_const(rng).begin();
} else {
return rng.begin();
}
};
auto getEnd = [](auto&& rng) {
if constexpr (ConstSent) {
return std::as_const(rng).end();
} else {
return rng.end();
}
};
// iter == sentinel.base
{
int buffer[] = {1};
R v{buffer};
std::ranges::take_while_view twv(v, LessThan3{});
auto iter = getBegin(twv);
auto st = getEnd(twv);
++iter;
assert(iter == st);
}
// iter != sentinel.base && pred(*iter)
{
int buffer[] = {1, 3, 4};
R v{buffer};
std::ranges::take_while_view twv(v, LessThan3{});
auto iter = getBegin(twv);
auto st = getEnd(twv);
assert(iter != st);
++iter;
assert(iter == st);
}
// iter != sentinel.base && !pred(*iter)
{
int buffer[] = {1, 2, 3, 4, 3, 2, 1};
R v{buffer};
std::ranges::take_while_view twv(v, LessThan3{});
auto iter = getBegin(twv);
auto sent = getEnd(twv);
assert(iter != sent);
}
// empty range
{
std::array<int, 0> arr;
R v{arr};
std::ranges::take_while_view twv(v, LessThan3{});
auto iter = getBegin(twv);
auto sent = getEnd(twv);
assert(iter == sent);
}
}
constexpr bool test() {
testOne<R, false, false>();
testOne<R, true, true>();
testOne<CrossComparableR, false, false>();
testOne<CrossComparableR, true, true>();
// LWG 3449 `take_view` and `take_while_view`'s `sentinel<false>` not comparable with their const iterator
testOne<CrossComparableR, true, false>();
testOne<CrossComparableR, false, true>();
// test std::invoke is used
{
struct Data {
bool b;
};
Data buffer[] = {{true}, {true}, {false}};
std::ranges::take_while_view twv(buffer, &Data::b);
auto it = twv.begin();
auto st = twv.end();
assert(it != st);
++it;
assert(it != st);
++it;
assert(it == st);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,59 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_TAKE_WHILE_TYPES_H
#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_TAKE_WHILE_TYPES_H
#include <array>
#include <functional>
#include <ranges>
#include "test_macros.h"
#include "test_iterators.h"
#include "test_range.h"
template <class T>
struct BufferViewBase : std::ranges::view_base {
T* buffer_;
std::size_t size_;
template <std::size_t N>
constexpr BufferViewBase(T (&b)[N]) : buffer_(b), size_(N) {}
template <std::size_t N>
constexpr BufferViewBase(std::array<T, N>& arr) : buffer_(arr.data()), size_(N) {}
};
using IntBufferViewBase = BufferViewBase<int>;
struct SimpleView : IntBufferViewBase {
using IntBufferViewBase::IntBufferViewBase;
constexpr int* begin() const { return buffer_; }
constexpr int* end() const { return buffer_ + size_; }
};
LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<SimpleView>);
struct ConstNotRange : IntBufferViewBase {
using IntBufferViewBase::IntBufferViewBase;
constexpr int* begin() { return buffer_; }
constexpr int* end() { return buffer_ + size_; }
};
static_assert(std::ranges::view<ConstNotRange>);
static_assert(!std::ranges::range<const ConstNotRange>);
struct NonSimple : IntBufferViewBase {
using IntBufferViewBase::IntBufferViewBase;
constexpr const int* begin() const { return buffer_; }
constexpr const int* end() const { return buffer_ + size_; }
constexpr int* begin() { return buffer_; }
constexpr int* end() { return buffer_ + size_; }
};
static_assert(std::ranges::view<NonSimple>);
LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<NonSimple>);
#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_TAKE_WHILE_TYPES_H