[libc++][ranges]implement `std::views::take_while`
Differential Revision: https://reviews.llvm.org/D134952
This commit is contained in:
parent
b72a364bb5
commit
a2c6a1193f
|
@ -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"
|
||||
|
|
|
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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'}}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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>>);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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>>);
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue