forked from OSchip/llvm-project
[libc++] Implement ranges::filter_view
Differential Revision: https://reviews.llvm.org/D109086
This commit is contained in:
parent
27e8c50a4c
commit
2b424f4ea8
|
@ -151,7 +151,7 @@ Section,Description,Dependencies,Assignee,Complete
|
|||
`[range.iota] <https://wg21.link/range.iota>`_,`iota_view <https://llvm.org/D107396>`_,[range.all],Zoe Carver,✅
|
||||
`[range.all] <https://wg21.link/range.all>`_,`view::all <https://llvm.org/D102028>`_,"[range.subrange], [range.view.ref]",Zoe Carver,✅
|
||||
`[range.ref.view] <https://wg21.link/range.ref.view>`_,`ref_view <https://llvm.org/D102020>`_,[view.interface],Zoe Carver,✅
|
||||
`[range.filter] <https://wg21.link/range.filter>`_,`filter_view <https://llvm.org/D109086>`_,[range.all],Louis Dionne,Under review
|
||||
`[range.filter] <https://wg21.link/range.filter>`_,`filter_view <https://llvm.org/D109086>`_,[range.all],Louis Dionne,✅
|
||||
`[range.transform] <https://wg21.link/range.transform>`_,`transform_view <https://llvm.org/D103056>`_,[range.all],Zoe Carver,✅
|
||||
`[range.take] <https://wg21.link/range.take>`_,`take_view <https://llvm.org/D106507>`_,[range.all],Zoe Carver,✅
|
||||
`[range.join] <https://wg21.link/range.join>`_,`join_view <https://llvm.org/D107671>`_,[range.all],Zoe Carver,✅
|
||||
|
|
|
|
@ -371,6 +371,7 @@ set(files
|
|||
__ranges/empty_view.h
|
||||
__ranges/enable_borrowed_range.h
|
||||
__ranges/enable_view.h
|
||||
__ranges/filter_view.h
|
||||
__ranges/iota_view.h
|
||||
__ranges/join_view.h
|
||||
__ranges/lazy_split_view.h
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
// -*- 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_FILTER_VIEW_H
|
||||
#define _LIBCPP___RANGES_FILTER_VIEW_H
|
||||
|
||||
#include <__algorithm/ranges_find_if.h>
|
||||
#include <__config>
|
||||
#include <__debug>
|
||||
#include <__functional/bind_back.h>
|
||||
#include <__functional/invoke.h>
|
||||
#include <__functional/reference_wrapper.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/iter_move.h>
|
||||
#include <__iterator/iter_swap.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/all.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/copyable_box.h>
|
||||
#include <__ranges/non_propagating_cache.h>
|
||||
#include <__ranges/range_adaptor.h>
|
||||
#include <__ranges/view_interface.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/in_place.h>
|
||||
#include <__utility/move.h>
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||
|
||||
namespace ranges {
|
||||
template<input_range _View, indirect_unary_predicate<iterator_t<_View>> _Pred>
|
||||
requires view<_View> && is_object_v<_Pred>
|
||||
class filter_view : public view_interface<filter_view<_View, _Pred>> {
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS __copyable_box<_Pred> __pred_;
|
||||
|
||||
// We cache the result of begin() to allow providing an amortized O(1) begin() whenever
|
||||
// the underlying range is at least a forward_range.
|
||||
static constexpr bool _UseCache = forward_range<_View>;
|
||||
using _Cache = _If<_UseCache, __non_propagating_cache<iterator_t<_View>>, __empty_cache>;
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _Cache __cached_begin_ = _Cache();
|
||||
|
||||
class __iterator;
|
||||
class __sentinel;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
filter_view() requires default_initializable<_View> && default_initializable<_Pred> = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr filter_view(_View __base, _Pred __pred)
|
||||
: __base_(std::move(__base)), __pred_(in_place, std::move(__pred))
|
||||
{ }
|
||||
|
||||
template<class _Vp = _View>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr _View base() const& requires copy_constructible<_Vp> { return __base_; }
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr _View base() && { return std::move(__base_); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr _Pred const& pred() const { return *__pred_; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __iterator begin() {
|
||||
_LIBCPP_ASSERT(__pred_.__has_value(), "Trying to call begin() on a filter_view that does not have a valid predicate.");
|
||||
if constexpr (_UseCache) {
|
||||
if (!__cached_begin_.__has_value()) {
|
||||
__cached_begin_.__emplace(ranges::find_if(__base_, std::ref(*__pred_)));
|
||||
}
|
||||
return {*this, *__cached_begin_};
|
||||
} else {
|
||||
return {*this, ranges::find_if(__base_, std::ref(*__pred_))};
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr auto end() {
|
||||
if constexpr (common_range<_View>)
|
||||
return __iterator{*this, ranges::end(__base_)};
|
||||
else
|
||||
return __sentinel{*this};
|
||||
}
|
||||
};
|
||||
|
||||
template<class _Range, class _Pred>
|
||||
filter_view(_Range&&, _Pred) -> filter_view<views::all_t<_Range>, _Pred>;
|
||||
|
||||
template<class _View>
|
||||
struct __filter_iterator_category { };
|
||||
|
||||
template<forward_range _View>
|
||||
struct __filter_iterator_category<_View> {
|
||||
using _Cat = typename iterator_traits<iterator_t<_View>>::iterator_category;
|
||||
using iterator_category =
|
||||
_If<derived_from<_Cat, bidirectional_iterator_tag>, bidirectional_iterator_tag,
|
||||
_If<derived_from<_Cat, forward_iterator_tag>, forward_iterator_tag,
|
||||
/* else */ _Cat
|
||||
>>;
|
||||
};
|
||||
|
||||
template<input_range _View, indirect_unary_predicate<iterator_t<_View>> _Pred>
|
||||
requires view<_View> && is_object_v<_Pred>
|
||||
class filter_view<_View, _Pred>::__iterator : public __filter_iterator_category<_View> {
|
||||
public:
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_View> __current_ = iterator_t<_View>();
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS filter_view* __parent_ = nullptr;
|
||||
|
||||
using iterator_concept =
|
||||
_If<bidirectional_range<_View>, bidirectional_iterator_tag,
|
||||
_If<forward_range<_View>, forward_iterator_tag,
|
||||
/* else */ input_iterator_tag
|
||||
>>;
|
||||
// using iterator_category = inherited;
|
||||
using value_type = range_value_t<_View>;
|
||||
using difference_type = range_difference_t<_View>;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
__iterator() requires default_initializable<iterator_t<_View>> = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __iterator(filter_view& __parent, iterator_t<_View> __current)
|
||||
: __current_(std::move(__current)), __parent_(std::addressof(__parent))
|
||||
{ }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr iterator_t<_View> const& base() const& noexcept { return __current_; }
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr iterator_t<_View> base() && { return std::move(__current_); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr range_reference_t<_View> operator*() const { return *__current_; }
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr iterator_t<_View> operator->() const
|
||||
requires __has_arrow<iterator_t<_View>> && copyable<iterator_t<_View>>
|
||||
{
|
||||
return __current_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __iterator& operator++() {
|
||||
__current_ = ranges::find_if(std::move(++__current_), ranges::end(__parent_->__base_),
|
||||
std::ref(*__parent_->__pred_));
|
||||
return *this;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr void operator++(int) { ++*this; }
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __iterator operator++(int) requires forward_range<_View> {
|
||||
auto __tmp = *this;
|
||||
++*this;
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __iterator& operator--() requires bidirectional_range<_View> {
|
||||
do {
|
||||
--__current_;
|
||||
} while (!std::invoke(*__parent_->__pred_, *__current_));
|
||||
return *this;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __iterator operator--(int) requires bidirectional_range<_View> {
|
||||
auto tmp = *this;
|
||||
--*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
friend constexpr bool operator==(__iterator const& __x, __iterator const& __y)
|
||||
requires equality_comparable<iterator_t<_View>>
|
||||
{
|
||||
return __x.__current_ == __y.__current_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
friend constexpr range_rvalue_reference_t<_View> iter_move(__iterator const& __it)
|
||||
noexcept(noexcept(ranges::iter_move(__it.__current_)))
|
||||
{
|
||||
return ranges::iter_move(__it.__current_);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
friend constexpr void iter_swap(__iterator const& __x, __iterator const& __y)
|
||||
noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_)))
|
||||
requires indirectly_swappable<iterator_t<_View>>
|
||||
{
|
||||
return ranges::iter_swap(__x.__current_, __y.__current_);
|
||||
}
|
||||
};
|
||||
|
||||
template<input_range _View, indirect_unary_predicate<iterator_t<_View>> _Pred>
|
||||
requires view<_View> && is_object_v<_Pred>
|
||||
class filter_view<_View, _Pred>::__sentinel {
|
||||
public:
|
||||
sentinel_t<_View> __end_ = sentinel_t<_View>();
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
__sentinel() = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr explicit __sentinel(filter_view& __parent)
|
||||
: __end_(ranges::end(__parent.__base_))
|
||||
{ }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr sentinel_t<_View> base() const { return __end_; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
friend constexpr bool operator==(__iterator const& __x, __sentinel const& __y) {
|
||||
return __x.__current_ == __y.__end_;
|
||||
}
|
||||
};
|
||||
|
||||
namespace views {
|
||||
namespace __filter {
|
||||
struct __fn {
|
||||
template<class _Range, class _Pred>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
|
||||
constexpr auto operator()(_Range&& __range, _Pred&& __pred) const
|
||||
noexcept(noexcept(filter_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred))))
|
||||
-> decltype( filter_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred)))
|
||||
{ return filter_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 __filter
|
||||
|
||||
inline namespace __cpo {
|
||||
inline constexpr auto filter = __filter::__fn{};
|
||||
} // namespace __cpo
|
||||
} // namespace views
|
||||
|
||||
} // namespace ranges
|
||||
|
||||
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___RANGES_FILTER_VIEW_H
|
|
@ -849,6 +849,7 @@ module std [system] {
|
|||
module empty_view { private header "__ranges/empty_view.h" }
|
||||
module enable_borrowed_range { private header "__ranges/enable_borrowed_range.h" }
|
||||
module enable_view { private header "__ranges/enable_view.h" }
|
||||
module filter_view { private header "__ranges/filter_view.h" }
|
||||
module iota_view { private header "__ranges/iota_view.h" }
|
||||
module join_view { private header "__ranges/join_view.h" }
|
||||
module lazy_split_view { private header "__ranges/lazy_split_view.h" }
|
||||
|
|
|
@ -150,6 +150,15 @@ namespace std::ranges {
|
|||
template<class T>
|
||||
inline constexpr bool enable_borrowed_range<owning_view<T>> = enable_borrowed_range<T>;
|
||||
|
||||
// [range.filter], filter view
|
||||
template<input_range V, indirect_unary_predicate<iterator_t<V>> Pred>
|
||||
requires view<V> && is_object_v<Pred>
|
||||
class filter_view;
|
||||
|
||||
namespace views {
|
||||
inline constexpr unspecified filter = unspecified;
|
||||
}
|
||||
|
||||
// [range.drop], drop view
|
||||
template<view V>
|
||||
class drop_view;
|
||||
|
@ -266,6 +275,7 @@ namespace std {
|
|||
#include <__ranges/empty_view.h>
|
||||
#include <__ranges/enable_borrowed_range.h>
|
||||
#include <__ranges/enable_view.h>
|
||||
#include <__ranges/filter_view.h>
|
||||
#include <__ranges/iota_view.h>
|
||||
#include <__ranges/join_view.h>
|
||||
#include <__ranges/lazy_split_view.h>
|
||||
|
|
|
@ -402,6 +402,7 @@ END-SCRIPT
|
|||
#include <__ranges/empty_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/empty_view.h'}}
|
||||
#include <__ranges/enable_borrowed_range.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/enable_borrowed_range.h'}}
|
||||
#include <__ranges/enable_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/enable_view.h'}}
|
||||
#include <__ranges/filter_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/filter_view.h'}}
|
||||
#include <__ranges/iota_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/iota_view.h'}}
|
||||
#include <__ranges/join_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/join_view.h'}}
|
||||
#include <__ranges/lazy_split_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/lazy_split_view.h'}}
|
||||
|
|
|
@ -89,7 +89,7 @@ static_assert(test(std::views::counted, a, 10));
|
|||
//static_assert(test(std::views::drop, a, 10));
|
||||
//static_assert(test(std::views::drop_while, a, [](int x){ return x < 10; }));
|
||||
//static_assert(test(std::views::elements<0>, pairs));
|
||||
//static_assert(test(std::views::filter, a, [](int x){ return x < 10; }));
|
||||
static_assert(test(std::views::filter, a, [](int x){ return x < 10; }));
|
||||
//static_assert(test(std::views::join, arrays));
|
||||
static_assert(test(std::views::lazy_split, a, 4));
|
||||
static_assert(test(std::views::reverse, a));
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::views::filter
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "test_iterators.h"
|
||||
|
||||
template <class View, class T>
|
||||
concept CanBePiped = requires (View&& view, T&& t) {
|
||||
{ std::forward<View>(view) | std::forward<T>(t) };
|
||||
};
|
||||
|
||||
struct NonCopyablePredicate {
|
||||
NonCopyablePredicate(NonCopyablePredicate const&) = delete;
|
||||
template <class T>
|
||||
constexpr bool operator()(T x) const { return x % 2 == 0; }
|
||||
};
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
using Iterator = forward_iterator<int*>;
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) { }
|
||||
constexpr Iterator begin() const { return Iterator(begin_); }
|
||||
constexpr Sentinel end() const { return Sentinel(Iterator(end_)); }
|
||||
|
||||
private:
|
||||
int* begin_;
|
||||
int* end_;
|
||||
};
|
||||
|
||||
struct Pred {
|
||||
constexpr bool operator()(int i) const { return i % 2 == 0; }
|
||||
};
|
||||
|
||||
template <typename View>
|
||||
constexpr void compareViews(View v, std::initializer_list<int> list) {
|
||||
auto b1 = v.begin();
|
||||
auto e1 = v.end();
|
||||
auto b2 = list.begin();
|
||||
auto e2 = list.end();
|
||||
for (; b1 != e1 && b2 != e2; ++b1, ++b2) {
|
||||
assert(*b1 == *b2);
|
||||
}
|
||||
assert(b1 == e1);
|
||||
assert(b2 == e2);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
int buff[] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
// Test `views::filter(pred)(v)`
|
||||
{
|
||||
using Result = std::ranges::filter_view<Range, Pred>;
|
||||
Range const range(buff, buff + 8);
|
||||
Pred pred;
|
||||
|
||||
{
|
||||
std::same_as<Result> decltype(auto) result = std::views::filter(pred)(range);
|
||||
compareViews(result, {0, 2, 4, 6});
|
||||
}
|
||||
{
|
||||
auto const partial = std::views::filter(pred);
|
||||
std::same_as<Result> decltype(auto) result = partial(range);
|
||||
compareViews(result, {0, 2, 4, 6});
|
||||
}
|
||||
}
|
||||
|
||||
// Test `v | views::filter(pred)`
|
||||
{
|
||||
using Result = std::ranges::filter_view<Range, Pred>;
|
||||
Range const range(buff, buff + 8);
|
||||
Pred pred;
|
||||
|
||||
{
|
||||
std::same_as<Result> decltype(auto) result = range | std::views::filter(pred);
|
||||
compareViews(result, {0, 2, 4, 6});
|
||||
}
|
||||
{
|
||||
auto const partial = std::views::filter(pred);
|
||||
std::same_as<Result> decltype(auto) result = range | partial;
|
||||
compareViews(result, {0, 2, 4, 6});
|
||||
}
|
||||
}
|
||||
|
||||
// Test `views::filter(v, pred)`
|
||||
{
|
||||
using Result = std::ranges::filter_view<Range, Pred>;
|
||||
Range const range(buff, buff + 8);
|
||||
Pred pred;
|
||||
|
||||
std::same_as<Result> decltype(auto) result = std::views::filter(range, pred);
|
||||
compareViews(result, {0, 2, 4, 6});
|
||||
}
|
||||
|
||||
// Test that one can call std::views::filter with arbitrary stuff, as long as we
|
||||
// don't try to actually complete the call by passing it a range.
|
||||
//
|
||||
// That makes no sense and we can't do anything with the result, but it's valid.
|
||||
{
|
||||
struct X { };
|
||||
[[maybe_unused]] auto partial = std::views::filter(X{});
|
||||
}
|
||||
|
||||
// Test `adaptor | views::filter(pred)`
|
||||
{
|
||||
Range const range(buff, buff + 8);
|
||||
|
||||
{
|
||||
auto pred1 = [](int i) { return i % 2 == 0; };
|
||||
auto pred2 = [](int i) { return i % 3 == 0; };
|
||||
using Result = std::ranges::filter_view<std::ranges::filter_view<Range, decltype(pred1)>, decltype(pred2)>;
|
||||
std::same_as<Result> decltype(auto) result = range | std::views::filter(pred1) | std::views::filter(pred2);
|
||||
compareViews(result, {0, 6});
|
||||
}
|
||||
{
|
||||
auto pred1 = [](int i) { return i % 2 == 0; };
|
||||
auto pred2 = [](int i) { return i % 3 == 0; };
|
||||
using Result = std::ranges::filter_view<std::ranges::filter_view<Range, decltype(pred1)>, decltype(pred2)>;
|
||||
auto const partial = std::views::filter(pred1) | std::views::filter(pred2);
|
||||
std::same_as<Result> decltype(auto) result = range | partial;
|
||||
compareViews(result, {0, 6});
|
||||
}
|
||||
}
|
||||
|
||||
// Test SFINAE friendliness
|
||||
{
|
||||
struct NotAView { };
|
||||
struct NotInvocable { };
|
||||
|
||||
static_assert(!CanBePiped<Range, decltype(std::views::filter)>);
|
||||
static_assert( CanBePiped<Range, decltype(std::views::filter(Pred{}))>);
|
||||
static_assert(!CanBePiped<NotAView, decltype(std::views::filter(Pred{}))>);
|
||||
static_assert(!CanBePiped<Range, decltype(std::views::filter(NotInvocable{}))>);
|
||||
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::filter)>);
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::filter), Pred, Range>);
|
||||
static_assert( std::is_invocable_v<decltype(std::views::filter), Range, Pred>);
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::filter), Range, Pred, Pred>);
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::filter), NonCopyablePredicate>);
|
||||
}
|
||||
|
||||
{
|
||||
static_assert(std::is_same_v<decltype(std::ranges::views::filter), decltype(std::views::filter)>);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr View base() const& requires copy_constructible<View>;
|
||||
// constexpr View base() &&;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) { }
|
||||
constexpr Range(Range const& other) : begin_(other.begin_), end_(other.end_), wasCopyInitialized(true) { }
|
||||
constexpr Range(Range&& other) : begin_(other.begin_), end_(other.end_), wasMoveInitialized(true) { }
|
||||
Range& operator=(Range const&) = default;
|
||||
Range& operator=(Range&&) = default;
|
||||
constexpr int* begin() const { return begin_; }
|
||||
constexpr int* end() const { return end_; }
|
||||
|
||||
int* begin_;
|
||||
int* end_;
|
||||
bool wasCopyInitialized = false;
|
||||
bool wasMoveInitialized = false;
|
||||
};
|
||||
|
||||
struct Pred {
|
||||
bool operator()(int) const;
|
||||
};
|
||||
|
||||
struct NoCopyRange : std::ranges::view_base {
|
||||
explicit NoCopyRange(int*, int*);
|
||||
NoCopyRange(NoCopyRange const&) = delete;
|
||||
NoCopyRange(NoCopyRange&&) = default;
|
||||
NoCopyRange& operator=(NoCopyRange const&) = default;
|
||||
NoCopyRange& operator=(NoCopyRange&&) = default;
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept can_call_base_on = requires(T t) { std::forward<T>(t).base(); };
|
||||
|
||||
constexpr bool test() {
|
||||
int buff[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
// Check the const& overload
|
||||
{
|
||||
Range range(buff, buff + 8);
|
||||
std::ranges::filter_view<Range, Pred> const view(range, Pred{});
|
||||
std::same_as<Range> decltype(auto) result = view.base();
|
||||
assert(result.wasCopyInitialized);
|
||||
assert(result.begin() == buff);
|
||||
assert(result.end() == buff + 8);
|
||||
}
|
||||
|
||||
// Check the && overload
|
||||
{
|
||||
Range range(buff, buff + 8);
|
||||
std::ranges::filter_view<Range, Pred> view(range, Pred{});
|
||||
std::same_as<Range> decltype(auto) result = std::move(view).base();
|
||||
assert(result.wasMoveInitialized);
|
||||
assert(result.begin() == buff);
|
||||
assert(result.end() == buff + 8);
|
||||
}
|
||||
|
||||
// Ensure the const& overload is not considered when the base is not copy-constructible
|
||||
{
|
||||
static_assert(!can_call_base_on<std::ranges::filter_view<NoCopyRange, Pred> const&>);
|
||||
static_assert(!can_call_base_on<std::ranges::filter_view<NoCopyRange, Pred>&>);
|
||||
static_assert( can_call_base_on<std::ranges::filter_view<NoCopyRange, Pred>&&>);
|
||||
static_assert( can_call_base_on<std::ranges::filter_view<NoCopyRange, Pred>>);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr iterator begin();
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include "test_iterators.h"
|
||||
#include "types.h"
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
using Iterator = forward_iterator<int*>;
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) { }
|
||||
constexpr Iterator begin() const { return Iterator(begin_); }
|
||||
constexpr Sentinel end() const { return Sentinel(Iterator(end_)); }
|
||||
|
||||
private:
|
||||
int* begin_;
|
||||
int* end_;
|
||||
};
|
||||
|
||||
// A range that isn't a forward_range, used to test filter_view
|
||||
// when we don't cache the result of begin()
|
||||
struct InputRange : std::ranges::view_base {
|
||||
using Iterator = cpp17_input_iterator<int*>;
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
constexpr explicit InputRange(int* b, int* e) : begin_(b), end_(e) { }
|
||||
constexpr Iterator begin() const { return Iterator(begin_); }
|
||||
constexpr Sentinel end() const { return Sentinel(Iterator(end_)); }
|
||||
|
||||
private:
|
||||
int* begin_;
|
||||
int* end_;
|
||||
};
|
||||
|
||||
struct TrackingPred : TrackInitialization {
|
||||
using TrackInitialization::TrackInitialization;
|
||||
constexpr bool operator()(int i) const { return i % 2 == 0; }
|
||||
};
|
||||
|
||||
template <typename Range>
|
||||
constexpr void general_tests() {
|
||||
int buff[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
// Check the return type of `.begin()`
|
||||
{
|
||||
Range range(buff, buff + 1);
|
||||
auto pred = [](int) { return true; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
using FilterIterator = std::ranges::iterator_t<decltype(view)>;
|
||||
ASSERT_SAME_TYPE(FilterIterator, decltype(view.begin()));
|
||||
}
|
||||
|
||||
// begin() over an empty range
|
||||
{
|
||||
Range range(buff, buff);
|
||||
auto pred = [](int) { return true; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base(it.base()) == buff);
|
||||
assert(it == view.end());
|
||||
}
|
||||
|
||||
// begin() over a 1-element range
|
||||
{
|
||||
{
|
||||
Range range(buff, buff + 1);
|
||||
auto pred = [](int i) { return i == 1; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base(it.base()) == buff);
|
||||
}
|
||||
{
|
||||
Range range(buff, buff + 1);
|
||||
auto pred = [](int) { return false; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base(it.base()) == buff + 1);
|
||||
assert(it == view.end());
|
||||
}
|
||||
}
|
||||
|
||||
// begin() over a 2-element range
|
||||
{
|
||||
{
|
||||
Range range(buff, buff + 2);
|
||||
auto pred = [](int i) { return i == 1; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base(it.base()) == buff);
|
||||
}
|
||||
{
|
||||
Range range(buff, buff + 2);
|
||||
auto pred = [](int i) { return i == 2; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base(it.base()) == buff + 1);
|
||||
}
|
||||
{
|
||||
Range range(buff, buff + 2);
|
||||
auto pred = [](int) { return false; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base(it.base()) == buff + 2);
|
||||
assert(it == view.end());
|
||||
}
|
||||
}
|
||||
|
||||
// begin() over a N-element range
|
||||
{
|
||||
for (int k = 1; k != 8; ++k) {
|
||||
Range range(buff, buff + 8);
|
||||
auto pred = [=](int i) { return i == k; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base(it.base()) == buff + (k - 1));
|
||||
}
|
||||
{
|
||||
Range range(buff, buff + 8);
|
||||
auto pred = [](int) { return false; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base(it.base()) == buff + 8);
|
||||
assert(it == view.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we do not make a copy of the predicate when we call begin()
|
||||
// (we should be passing it to ranges::find_if using std::ref)
|
||||
{
|
||||
bool moved = false, copied = false;
|
||||
Range range(buff, buff + 2);
|
||||
std::ranges::filter_view view(range, TrackingPred(&moved, &copied));
|
||||
moved = false;
|
||||
copied = false;
|
||||
[[maybe_unused]] auto it = view.begin();
|
||||
assert(!moved);
|
||||
assert(!copied);
|
||||
}
|
||||
|
||||
// Test with a non-const predicate
|
||||
{
|
||||
Range range(buff, buff + 8);
|
||||
auto pred = [](int i) mutable { return i % 2 == 0; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base(it.base()) == buff + 1);
|
||||
}
|
||||
|
||||
// Test with a predicate that takes by non-const reference
|
||||
{
|
||||
Range range(buff, buff + 8);
|
||||
auto pred = [](int& i) { return i % 2 == 0; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto it = view.begin();
|
||||
assert(base(it.base()) == buff + 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ForwardRange>
|
||||
constexpr void cache_tests() {
|
||||
int buff[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
// Make sure that we cache the result of begin() on subsequent calls
|
||||
// (only applies to forward_ranges)
|
||||
ForwardRange range(buff, buff + 8);
|
||||
int called = 0;
|
||||
auto pred = [&](int i) { ++called; return i == 3; };
|
||||
|
||||
std::ranges::filter_view view(range, pred);
|
||||
assert(called == 0);
|
||||
for (int k = 0; k != 3; ++k) {
|
||||
auto it = view.begin();
|
||||
assert(base(it.base()) == buff + 2);
|
||||
assert(called == 3);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
general_tests<Range>();
|
||||
general_tests<InputRange>(); // test when we don't cache the result
|
||||
cache_tests<Range>();
|
||||
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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// Check constraints on the type itself.
|
||||
//
|
||||
// template<input_range View, indirect_unary_predicate<iterator_t<View>> Pred>
|
||||
// requires view<View> && is_object_v<Pred>
|
||||
// class filter_view;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
template <class View, class Pred>
|
||||
concept can_form_filter_view = requires {
|
||||
typename std::ranges::filter_view<View, Pred>;
|
||||
};
|
||||
|
||||
// filter_view is not valid when the view is not an input_range
|
||||
namespace test1 {
|
||||
struct View : std::ranges::view_base {
|
||||
struct NotInputIterator {
|
||||
NotInputIterator& operator++();
|
||||
void operator++(int);
|
||||
int& operator*() const;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
friend bool operator==(NotInputIterator const&, NotInputIterator const&);
|
||||
};
|
||||
NotInputIterator begin() const;
|
||||
NotInputIterator end() const;
|
||||
};
|
||||
struct Pred { bool operator()(int) const; };
|
||||
|
||||
static_assert(!std::ranges::input_range<View>);
|
||||
static_assert( std::indirect_unary_predicate<Pred, int*>);
|
||||
static_assert( std::ranges::view<View>);
|
||||
static_assert( std::is_object_v<Pred>);
|
||||
static_assert(!can_form_filter_view<View, Pred>);
|
||||
}
|
||||
|
||||
// filter_view is not valid when the predicate is not indirect_unary_predicate
|
||||
namespace test2 {
|
||||
struct View : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
struct Pred { };
|
||||
|
||||
static_assert( std::ranges::input_range<View>);
|
||||
static_assert(!std::indirect_unary_predicate<Pred, int*>);
|
||||
static_assert( std::ranges::view<View>);
|
||||
static_assert( std::is_object_v<Pred>);
|
||||
static_assert(!can_form_filter_view<View, Pred>);
|
||||
}
|
||||
|
||||
// filter_view is not valid when the view is not a view
|
||||
namespace test3 {
|
||||
struct View {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
struct Pred { bool operator()(int) const; };
|
||||
|
||||
static_assert( std::ranges::input_range<View>);
|
||||
static_assert( std::indirect_unary_predicate<Pred, int*>);
|
||||
static_assert(!std::ranges::view<View>);
|
||||
static_assert( std::is_object_v<Pred>);
|
||||
static_assert(!can_form_filter_view<View, Pred>);
|
||||
}
|
||||
|
||||
// filter_view is not valid when the predicate is not an object type
|
||||
namespace test4 {
|
||||
struct View : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
using Pred = bool(&)(int);
|
||||
|
||||
static_assert( std::ranges::input_range<View>);
|
||||
static_assert( std::indirect_unary_predicate<Pred, int*>);
|
||||
static_assert( std::ranges::view<View>);
|
||||
static_assert(!std::is_object_v<Pred>);
|
||||
static_assert(!can_form_filter_view<View, Pred>);
|
||||
}
|
||||
|
||||
// filter_view is valid when all the constraints are satisfied (test the test)
|
||||
namespace test5 {
|
||||
struct View : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
struct Pred { bool operator()(int) const; };
|
||||
|
||||
static_assert( std::ranges::input_range<View>);
|
||||
static_assert( std::indirect_unary_predicate<Pred, int*>);
|
||||
static_assert( std::ranges::view<View>);
|
||||
static_assert( std::is_object_v<Pred>);
|
||||
static_assert( can_form_filter_view<View, Pred>);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// template <class Range, class Pred>
|
||||
// filter_view(Range&&, Pred) -> filter_view<views::all_t<Range>, Pred>;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include "test_iterators.h"
|
||||
|
||||
struct View : std::ranges::view_base {
|
||||
View() = default;
|
||||
forward_iterator<int*> begin() const;
|
||||
sentinel_wrapper<forward_iterator<int*>> end() const;
|
||||
};
|
||||
static_assert(std::ranges::view<View>);
|
||||
|
||||
// A range that is not a view
|
||||
struct Range {
|
||||
Range() = default;
|
||||
forward_iterator<int*> begin() const;
|
||||
sentinel_wrapper<forward_iterator<int*>> end() const;
|
||||
};
|
||||
static_assert(std::ranges::range<Range> && !std::ranges::view<Range>);
|
||||
|
||||
struct Pred {
|
||||
constexpr bool operator()(int i) const { return i % 2 == 0; }
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
View v;
|
||||
Pred pred;
|
||||
std::ranges::filter_view view(v, pred);
|
||||
static_assert(std::is_same_v<decltype(view), std::ranges::filter_view<View, Pred>>);
|
||||
}
|
||||
|
||||
// Test with a range that isn't a view, to make sure we properly use views::all_t in the implementation.
|
||||
{
|
||||
Range r;
|
||||
Pred pred;
|
||||
std::ranges::filter_view view(r, pred);
|
||||
static_assert(std::is_same_v<decltype(view), std::ranges::filter_view<std::ranges::ref_view<Range>, Pred>>);
|
||||
}
|
||||
|
||||
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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// filter_view() requires std::default_initializable<View> &&
|
||||
// std::default_initializable<Pred> = default;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
constexpr int buff[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
struct DefaultConstructibleView : std::ranges::view_base {
|
||||
constexpr DefaultConstructibleView() : begin_(buff), end_(buff + 8) { }
|
||||
constexpr int const* begin() const { return begin_; }
|
||||
constexpr int const* end() const { return end_; }
|
||||
private:
|
||||
int const* begin_;
|
||||
int const* end_;
|
||||
};
|
||||
|
||||
struct DefaultConstructiblePredicate {
|
||||
DefaultConstructiblePredicate() = default;
|
||||
constexpr bool operator()(int i) const { return i % 2 == 0; }
|
||||
};
|
||||
|
||||
struct NoDefaultView : std::ranges::view_base {
|
||||
NoDefaultView() = delete;
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
struct NoDefaultPredicate {
|
||||
NoDefaultPredicate() = delete;
|
||||
constexpr bool operator()(int) const;
|
||||
};
|
||||
|
||||
struct NoexceptView : std::ranges::view_base {
|
||||
NoexceptView() noexcept;
|
||||
int const* begin() const;
|
||||
int const* end() const;
|
||||
};
|
||||
|
||||
struct NoexceptPredicate {
|
||||
NoexceptPredicate() noexcept;
|
||||
bool operator()(int) const;
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
using View = std::ranges::filter_view<DefaultConstructibleView, DefaultConstructiblePredicate>;
|
||||
View view;
|
||||
auto it = view.begin(), end = view.end();
|
||||
assert(*it++ == 2);
|
||||
assert(*it++ == 4);
|
||||
assert(*it++ == 6);
|
||||
assert(*it++ == 8);
|
||||
assert(it == end);
|
||||
}
|
||||
|
||||
{
|
||||
using View = std::ranges::filter_view<DefaultConstructibleView, DefaultConstructiblePredicate>;
|
||||
View view = {};
|
||||
auto it = view.begin(), end = view.end();
|
||||
assert(*it++ == 2);
|
||||
assert(*it++ == 4);
|
||||
assert(*it++ == 6);
|
||||
assert(*it++ == 8);
|
||||
assert(it == end);
|
||||
}
|
||||
|
||||
// Check cases where the default constructor isn't provided
|
||||
{
|
||||
static_assert(!std::is_default_constructible_v<std::ranges::filter_view<NoDefaultView, DefaultConstructiblePredicate>>);
|
||||
static_assert(!std::is_default_constructible_v<std::ranges::filter_view<DefaultConstructibleView, NoDefaultPredicate>>);
|
||||
static_assert(!std::is_default_constructible_v<std::ranges::filter_view<NoDefaultView, NoDefaultPredicate>>);
|
||||
}
|
||||
|
||||
// Check noexcept-ness
|
||||
{
|
||||
{
|
||||
using View = std::ranges::filter_view<DefaultConstructibleView, DefaultConstructiblePredicate>;
|
||||
static_assert(!noexcept(View()));
|
||||
}
|
||||
{
|
||||
using View = std::ranges::filter_view<NoexceptView, NoexceptPredicate>;
|
||||
static_assert(noexcept(View()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr filter_view(View, Pred);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include "types.h"
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) { }
|
||||
constexpr int* begin() const { return begin_; }
|
||||
constexpr int* end() const { return end_; }
|
||||
|
||||
private:
|
||||
int* begin_;
|
||||
int* end_;
|
||||
};
|
||||
|
||||
struct Pred {
|
||||
constexpr bool operator()(int i) const { return i % 2 != 0; }
|
||||
};
|
||||
|
||||
struct TrackingPred : TrackInitialization {
|
||||
using TrackInitialization::TrackInitialization;
|
||||
constexpr bool operator()(int) const;
|
||||
};
|
||||
|
||||
struct TrackingRange : TrackInitialization, std::ranges::view_base {
|
||||
using TrackInitialization::TrackInitialization;
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
int buff[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
// Test explicit syntax
|
||||
{
|
||||
Range range(buff, buff + 8);
|
||||
Pred pred;
|
||||
std::ranges::filter_view<Range, Pred> view(range, pred);
|
||||
auto it = view.begin(), end = view.end();
|
||||
assert(*it++ == 1);
|
||||
assert(*it++ == 3);
|
||||
assert(*it++ == 5);
|
||||
assert(*it++ == 7);
|
||||
assert(it == end);
|
||||
}
|
||||
|
||||
// Test implicit syntax
|
||||
{
|
||||
Range range(buff, buff + 8);
|
||||
Pred pred;
|
||||
std::ranges::filter_view<Range, Pred> view = {range, pred};
|
||||
auto it = view.begin(), end = view.end();
|
||||
assert(*it++ == 1);
|
||||
assert(*it++ == 3);
|
||||
assert(*it++ == 5);
|
||||
assert(*it++ == 7);
|
||||
assert(it == end);
|
||||
}
|
||||
|
||||
// Make sure we move the view
|
||||
{
|
||||
bool moved = false, copied = false;
|
||||
TrackingRange range(&moved, &copied);
|
||||
Pred pred;
|
||||
[[maybe_unused]] std::ranges::filter_view<TrackingRange, Pred> view(std::move(range), pred);
|
||||
assert(moved);
|
||||
assert(!copied);
|
||||
}
|
||||
|
||||
// Make sure we move the predicate
|
||||
{
|
||||
bool moved = false, copied = false;
|
||||
Range range(buff, buff + 8);
|
||||
TrackingPred pred(&moved, &copied);
|
||||
[[maybe_unused]] std::ranges::filter_view<Range, TrackingPred> view(range, std::move(pred));
|
||||
assert(moved);
|
||||
assert(!copied);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr auto end();
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
#include "test_iterators.h"
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
using Iterator = forward_iterator<int*>;
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) { }
|
||||
constexpr Iterator begin() const { return Iterator(begin_); }
|
||||
constexpr Sentinel end() const { return Sentinel(Iterator(end_)); }
|
||||
|
||||
private:
|
||||
int* begin_;
|
||||
int* end_;
|
||||
};
|
||||
|
||||
struct CommonRange : std::ranges::view_base {
|
||||
using Iterator = forward_iterator<int*>;
|
||||
constexpr explicit CommonRange(int* b, int* e) : begin_(b), end_(e) { }
|
||||
constexpr Iterator begin() const { return Iterator(begin_); }
|
||||
constexpr Iterator end() const { return Iterator(end_); }
|
||||
|
||||
private:
|
||||
int* begin_;
|
||||
int* end_;
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
int buff[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
// Check the return type of `.end()`
|
||||
{
|
||||
Range range(buff, buff + 1);
|
||||
auto pred = [](int) { return true; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
using FilterSentinel = std::ranges::sentinel_t<decltype(view)>;
|
||||
ASSERT_SAME_TYPE(FilterSentinel, decltype(view.end()));
|
||||
}
|
||||
|
||||
// end() on an empty range
|
||||
{
|
||||
Range range(buff, buff);
|
||||
auto pred = [](int) { return true; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto end = view.end();
|
||||
assert(base(base(end.base())) == buff);
|
||||
}
|
||||
|
||||
// end() on a 1-element range
|
||||
{
|
||||
Range range(buff, buff + 1);
|
||||
auto pred = [](int) { return true; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto end = view.end();
|
||||
assert(base(base(end.base())) == buff + 1);
|
||||
static_assert(!std::is_same_v<decltype(end), decltype(view.begin())>);
|
||||
}
|
||||
|
||||
// end() on a 2-element range
|
||||
{
|
||||
Range range(buff, buff + 2);
|
||||
auto pred = [](int) { return true; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto end = view.end();
|
||||
assert(base(base(end.base())) == buff + 2);
|
||||
static_assert(!std::is_same_v<decltype(end), decltype(view.begin())>);
|
||||
}
|
||||
|
||||
// end() on a N-element range
|
||||
{
|
||||
for (int k = 1; k != 8; ++k) {
|
||||
Range range(buff, buff + 8);
|
||||
auto pred = [=](int i) { return i == k; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto end = view.end();
|
||||
assert(base(base(end.base())) == buff + 8);
|
||||
static_assert(!std::is_same_v<decltype(end), decltype(view.begin())>);
|
||||
}
|
||||
}
|
||||
|
||||
// end() on a common_range
|
||||
{
|
||||
CommonRange range(buff, buff + 8);
|
||||
auto pred = [](int i) { return i % 2 == 0; };
|
||||
std::ranges::filter_view view(range, pred);
|
||||
auto end = view.end();
|
||||
assert(base(end.base()) == buff + 8);
|
||||
static_assert(std::is_same_v<decltype(end), decltype(view.begin())>);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr iterator_t<V> operator->() const
|
||||
// requires has-arrow<iterator_t<V>> && copyable<iterator_t<V>>
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "../types.h"
|
||||
|
||||
struct Point {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
concept has_arrow = requires (T t) {
|
||||
{ t->x };
|
||||
};
|
||||
static_assert(has_arrow<Point*>); // test the test
|
||||
|
||||
struct WithArrowOperator {
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = Point;
|
||||
|
||||
constexpr explicit WithArrowOperator(Point* p) : p_(p) { }
|
||||
constexpr Point& operator*() const { return *p_; }
|
||||
constexpr Point* operator->() const { return p_; } // has arrow
|
||||
constexpr WithArrowOperator& operator++() { ++p_; return *this; }
|
||||
constexpr WithArrowOperator operator++(int) { return WithArrowOperator(p_++); }
|
||||
|
||||
friend constexpr Point* base(WithArrowOperator const& i) { return i.p_; }
|
||||
Point* p_;
|
||||
};
|
||||
static_assert(std::input_iterator<WithArrowOperator>);
|
||||
|
||||
struct WithNonCopyableIterator : std::ranges::view_base {
|
||||
struct iterator {
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = Point;
|
||||
|
||||
iterator(iterator const&) = delete; // not copyable
|
||||
iterator(iterator&&);
|
||||
iterator& operator=(iterator&&);
|
||||
Point& operator*() const;
|
||||
iterator operator->() const;
|
||||
iterator& operator++();
|
||||
iterator operator++(int);
|
||||
|
||||
// We need this to use Point* as a sentinel type below. sentinel_wrapper
|
||||
// can't be used because this iterator is not copyable.
|
||||
friend bool operator==(iterator const&, Point*);
|
||||
};
|
||||
|
||||
iterator begin() const;
|
||||
Point* end() const;
|
||||
};
|
||||
static_assert(std::ranges::input_range<WithNonCopyableIterator>);
|
||||
|
||||
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
|
||||
constexpr void test() {
|
||||
std::array<Point, 5> array{{{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}}};
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
|
||||
auto make_filter_view = [](auto begin, auto end, auto pred) {
|
||||
View view{Iterator(begin), Sentinel(Iterator(end))};
|
||||
return FilterView(std::move(view), pred);
|
||||
};
|
||||
|
||||
for (std::ptrdiff_t n = 0; n != 5; ++n) {
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), AlwaysTrue{});
|
||||
FilterIterator const iter(view, Iterator(array.begin() + n));
|
||||
std::same_as<Iterator> decltype(auto) result = iter.operator->();
|
||||
assert(base(result) == array.begin() + n);
|
||||
assert(iter->x == n);
|
||||
assert(iter->y == n);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<WithArrowOperator>();
|
||||
test<Point*>();
|
||||
test<Point const*>();
|
||||
test<contiguous_iterator<Point*>>();
|
||||
test<contiguous_iterator<Point const*>>();
|
||||
|
||||
// Make sure filter_view::iterator doesn't have operator-> if the
|
||||
// underlying iterator doesn't have one.
|
||||
{
|
||||
auto check_no_arrow = []<class It> {
|
||||
using View = minimal_view<It, sentinel_wrapper<It>>;
|
||||
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
static_assert(!has_arrow<FilterIterator>);
|
||||
};
|
||||
check_no_arrow.operator()<cpp17_input_iterator<Point*>>();
|
||||
check_no_arrow.operator()<cpp20_input_iterator<Point*>>();
|
||||
check_no_arrow.operator()<forward_iterator<Point*>>();
|
||||
check_no_arrow.operator()<bidirectional_iterator<Point*>>();
|
||||
check_no_arrow.operator()<random_access_iterator<Point*>>();
|
||||
check_no_arrow.operator()<int*>();
|
||||
}
|
||||
|
||||
// Make sure filter_view::iterator doesn't have operator-> if the
|
||||
// underlying iterator is not copyable.
|
||||
{
|
||||
using FilterView = std::ranges::filter_view<WithNonCopyableIterator, AlwaysTrue>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
static_assert(!has_arrow<FilterIterator>);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr iterator_t<V> const& base() const& noexcept;
|
||||
// constexpr iterator_t<V> base() &&;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
|
||||
constexpr void test() {
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
|
||||
auto make_filter_view = [](auto begin, auto end, auto pred) {
|
||||
View view{Iterator(begin), Sentinel(Iterator(end))};
|
||||
return FilterView(std::move(view), pred);
|
||||
};
|
||||
|
||||
std::array<int, 5> array{0, 1, 2, 3, 4};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), AlwaysTrue{});
|
||||
|
||||
// Test the const& version
|
||||
{
|
||||
FilterIterator const iter(view, Iterator(array.begin()));
|
||||
Iterator const& result = iter.base();
|
||||
ASSERT_SAME_TYPE(Iterator const&, decltype(iter.base()));
|
||||
ASSERT_NOEXCEPT(iter.base());
|
||||
assert(base(result) == array.begin());
|
||||
}
|
||||
|
||||
// Test the && version
|
||||
{
|
||||
FilterIterator iter(view, Iterator(array.begin()));
|
||||
Iterator result = std::move(iter).base();
|
||||
ASSERT_SAME_TYPE(Iterator, decltype(std::move(iter).base()));
|
||||
assert(base(result) == array.begin());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<cpp17_input_iterator<int*>>();
|
||||
test<cpp20_input_iterator<int*>>();
|
||||
test<forward_iterator<int*>>();
|
||||
test<bidirectional_iterator<int*>>();
|
||||
test<random_access_iterator<int*>>();
|
||||
test<contiguous_iterator<int*>>();
|
||||
test<int*>();
|
||||
test<int const*>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// friend constexpr bool operator==(iterator const&, iterator const&)
|
||||
// requires equality_comparable<iterator_t<V>>
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class T>
|
||||
concept has_equal = requires (T const& x, T const& y) { { x == y }; };
|
||||
|
||||
template <class Iterator>
|
||||
constexpr void test() {
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
|
||||
auto make_filter_view = [](auto begin, auto end, auto pred) {
|
||||
View view{Iterator(begin), Sentinel(Iterator(end))};
|
||||
return FilterView(std::move(view), pred);
|
||||
};
|
||||
|
||||
{
|
||||
std::array<int, 5> array{0, 1, 2, 3, 4};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), AlwaysTrue{});
|
||||
FilterIterator it1 = view.begin();
|
||||
FilterIterator it2 = view.begin();
|
||||
std::same_as<bool> decltype(auto) result = (it1 == it2);
|
||||
assert(result);
|
||||
|
||||
++it1;
|
||||
assert(!(it1 == it2));
|
||||
}
|
||||
|
||||
{
|
||||
std::array<int, 5> array{0, 1, 2, 3, 4};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), AlwaysTrue{});
|
||||
assert(!(view.begin() == view.end()));
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<cpp17_input_iterator<int*>>();
|
||||
test<forward_iterator<int*>>();
|
||||
test<bidirectional_iterator<int*>>();
|
||||
test<random_access_iterator<int*>>();
|
||||
test<contiguous_iterator<int*>>();
|
||||
test<int*>();
|
||||
|
||||
test<cpp17_input_iterator<int const*>>();
|
||||
test<forward_iterator<int const*>>();
|
||||
test<bidirectional_iterator<int const*>>();
|
||||
test<random_access_iterator<int const*>>();
|
||||
test<contiguous_iterator<int const*>>();
|
||||
test<int const*>();
|
||||
|
||||
// Make sure `operator==` isn't provided for non comparable iterators
|
||||
{
|
||||
using Iterator = cpp20_input_iterator<int*>;
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
using FilterView = std::ranges::filter_view<minimal_view<Iterator, Sentinel>, AlwaysTrue>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
static_assert(!has_equal<FilterIterator>);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::filter_view<V>::<iterator>() requires default_initializable<iterator_t<V>> = default;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include "test_iterators.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class Iterator, bool IsNoexcept>
|
||||
constexpr void test_default_constructible() {
|
||||
// Make sure the iterator is default constructible when the underlying iterator is.
|
||||
using View = minimal_view<Iterator, sentinel_wrapper<Iterator>>;
|
||||
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
FilterIterator iter1{};
|
||||
FilterIterator iter2;
|
||||
assert(iter1 == iter2);
|
||||
static_assert(noexcept(FilterIterator()) == IsNoexcept);
|
||||
}
|
||||
|
||||
template <class Iterator>
|
||||
constexpr void test_not_default_constructible() {
|
||||
// Make sure the iterator is *not* default constructible when the underlying iterator isn't.
|
||||
using View = minimal_view<Iterator, sentinel_wrapper<Iterator>>;
|
||||
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
static_assert(!std::is_default_constructible_v<FilterIterator>);
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test_not_default_constructible<cpp17_input_iterator<int*>>();
|
||||
test_not_default_constructible<cpp20_input_iterator<int*>>();
|
||||
test_default_constructible<forward_iterator<int*>, /* noexcept */ false>();
|
||||
test_default_constructible<bidirectional_iterator<int*>, /* noexcept */ false>();
|
||||
test_default_constructible<random_access_iterator<int*>, /* noexcept */ false>();
|
||||
test_default_constructible<contiguous_iterator<int*>, /* noexcept */ false>();
|
||||
test_default_constructible<int*, /* noexcept */ true>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr std::ranges::filter_view::<iterator>(filter_view&, iterator_t<V>);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
|
||||
constexpr void test() {
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
|
||||
std::array<int, 10> array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
View view(Iterator(array.begin()), Sentinel(Iterator(array.end())));
|
||||
Iterator iter = view.begin();
|
||||
|
||||
FilterView filter_view(std::move(view), AlwaysTrue{});
|
||||
FilterIterator filter_iter(filter_view, std::move(iter));
|
||||
assert(base(filter_iter.base()) == array.begin());
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<cpp17_input_iterator<int*>>();
|
||||
test<cpp20_input_iterator<int*>>();
|
||||
test<forward_iterator<int*>>();
|
||||
test<bidirectional_iterator<int*>>();
|
||||
test<random_access_iterator<int*>>();
|
||||
test<contiguous_iterator<int*>>();
|
||||
test<int*>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr iterator& operator--() requires bidirectional_range<V>;
|
||||
// constexpr iterator operator--(int) requires bidirectional_range<V>;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "../types.h"
|
||||
|
||||
struct EqualTo {
|
||||
int x;
|
||||
constexpr bool operator()(int y) const { return x == y; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
concept has_pre_decrement = requires (T t) { { --t }; };
|
||||
|
||||
template <class T>
|
||||
concept has_post_decrement = requires (T t) { { t-- }; };
|
||||
|
||||
template <class Iterator>
|
||||
using FilterIteratorFor = std::ranges::iterator_t<
|
||||
std::ranges::filter_view<minimal_view<Iterator, sentinel_wrapper<Iterator>>, EqualTo>
|
||||
>;
|
||||
|
||||
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
|
||||
constexpr void test() {
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
using FilterView = std::ranges::filter_view<View, EqualTo>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
|
||||
auto make_filter_view = [](auto begin, auto end, auto pred) {
|
||||
View view{Iterator(begin), Sentinel(Iterator(end))};
|
||||
return FilterView(std::move(view), pred);
|
||||
};
|
||||
|
||||
// Test with a single satisfied value
|
||||
{
|
||||
std::array<int, 5> array{0, 1, 2, 3, 4};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), EqualTo{1});
|
||||
FilterIterator it = std::ranges::next(view.begin(), view.end());
|
||||
assert(base(it.base()) == array.end()); // test the test
|
||||
|
||||
FilterIterator& result = --it;
|
||||
ASSERT_SAME_TYPE(FilterIterator&, decltype(--it));
|
||||
assert(&result == &it);
|
||||
assert(base(result.base()) == array.begin() + 1);
|
||||
}
|
||||
|
||||
// Test with more than one satisfied value
|
||||
{
|
||||
std::array<int, 6> array{0, 1, 2, 3, 1, 4};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), EqualTo{1});
|
||||
FilterIterator it = std::ranges::next(view.begin(), view.end());
|
||||
assert(base(it.base()) == array.end()); // test the test
|
||||
|
||||
FilterIterator& result = --it;
|
||||
assert(&result == &it);
|
||||
assert(base(result.base()) == array.begin() + 4);
|
||||
|
||||
--it;
|
||||
assert(base(it.base()) == array.begin() + 1);
|
||||
}
|
||||
|
||||
// Test going forward and then backward on the same iterator
|
||||
{
|
||||
std::array<int, 10> array{0, 1, 2, 3, 1, 1, 4, 5, 1, 6};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), EqualTo{1});
|
||||
FilterIterator it = view.begin();
|
||||
++it;
|
||||
--it; assert(base(it.base()) == array.begin() + 1);
|
||||
++it; ++it;
|
||||
--it; assert(base(it.base()) == array.begin() + 4);
|
||||
++it; ++it;
|
||||
--it; assert(base(it.base()) == array.begin() + 5);
|
||||
++it; ++it;
|
||||
--it; assert(base(it.base()) == array.begin() + 8);
|
||||
}
|
||||
|
||||
// Test post-decrement
|
||||
{
|
||||
std::array<int, 6> array{0, 1, 2, 3, 1, 4};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), EqualTo{1});
|
||||
FilterIterator it = std::ranges::next(view.begin(), view.end());
|
||||
assert(base(it.base()) == array.end()); // test the test
|
||||
|
||||
FilterIterator result = it--;
|
||||
ASSERT_SAME_TYPE(FilterIterator, decltype(it--));
|
||||
assert(base(result.base()) == array.end());
|
||||
assert(base(it.base()) == array.begin() + 4);
|
||||
|
||||
result = it--;
|
||||
assert(base(result.base()) == array.begin() + 4);
|
||||
assert(base(it.base()) == array.begin() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<bidirectional_iterator<int*>>();
|
||||
test<random_access_iterator<int*>>();
|
||||
test<contiguous_iterator<int*>>();
|
||||
test<int*>();
|
||||
|
||||
test<bidirectional_iterator<int const*>>();
|
||||
test<random_access_iterator<int const*>>();
|
||||
test<contiguous_iterator<int const*>>();
|
||||
test<int const*>();
|
||||
|
||||
// Make sure `operator--` isn't provided for non bidirectional ranges
|
||||
{
|
||||
static_assert(!has_pre_decrement<FilterIteratorFor<cpp17_input_iterator<int*>>>);
|
||||
static_assert(!has_pre_decrement<FilterIteratorFor<cpp20_input_iterator<int*>>>);
|
||||
static_assert(!has_pre_decrement<FilterIteratorFor<forward_iterator<int*>>>);
|
||||
|
||||
static_assert(!has_post_decrement<FilterIteratorFor<cpp17_input_iterator<int*>>>);
|
||||
static_assert(!has_post_decrement<FilterIteratorFor<cpp20_input_iterator<int*>>>);
|
||||
static_assert(!has_post_decrement<FilterIteratorFor<forward_iterator<int*>>>);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr range_reference_t<V> operator*() const;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class Iterator, class ValueType = int, class Sentinel = sentinel_wrapper<Iterator>>
|
||||
constexpr void test() {
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
|
||||
auto make_filter_view = [](auto begin, auto end, auto pred) {
|
||||
View view{Iterator(begin), Sentinel(Iterator(end))};
|
||||
return FilterView(std::move(view), pred);
|
||||
};
|
||||
|
||||
std::array array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), AlwaysTrue{});
|
||||
|
||||
for (std::size_t n = 0; n != array.size(); ++n) {
|
||||
FilterIterator const iter(view, Iterator(array.begin() + n));
|
||||
ValueType& result = *iter;
|
||||
ASSERT_SAME_TYPE(ValueType&, decltype(*iter));
|
||||
assert(&result == array.begin() + n);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<cpp17_input_iterator<int*>>();
|
||||
test<cpp20_input_iterator<int*>>();
|
||||
test<forward_iterator<int*>>();
|
||||
test<bidirectional_iterator<int*>>();
|
||||
test<random_access_iterator<int*>>();
|
||||
test<contiguous_iterator<int*>>();
|
||||
test<int*>();
|
||||
|
||||
test<cpp17_input_iterator<int const*>, int const>();
|
||||
test<cpp20_input_iterator<int const*>, int const>();
|
||||
test<forward_iterator<int const*>, int const>();
|
||||
test<bidirectional_iterator<int const*>, int const>();
|
||||
test<random_access_iterator<int const*>, int const>();
|
||||
test<contiguous_iterator<int const*>, int const>();
|
||||
test<int const*, int const>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr iterator& operator++();
|
||||
// constexpr void operator++(int);
|
||||
// constexpr iterator operator++(int) requires forward_range<V>;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "../types.h"
|
||||
|
||||
struct EqualTo {
|
||||
int x;
|
||||
constexpr bool operator()(int y) const { return x == y; }
|
||||
};
|
||||
|
||||
struct TrackingPred : TrackInitialization {
|
||||
using TrackInitialization::TrackInitialization;
|
||||
constexpr bool operator()(int i) const { return i == 1; }
|
||||
};
|
||||
|
||||
template <class Iterator, bool IsForwardRange, bool IsConst>
|
||||
constexpr void test() {
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
using FilterView = std::ranges::filter_view<View, EqualTo>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
|
||||
auto make_filter_view = [](auto begin, auto end, auto pred) {
|
||||
View view{Iterator(begin), Sentinel(Iterator(end))};
|
||||
return FilterView(std::move(view), pred);
|
||||
};
|
||||
|
||||
// Increment an iterator when it won't find another satisfied value after begin()
|
||||
{
|
||||
std::array<int, 5> array{0, 1, 2, 3, 4};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), EqualTo{1});
|
||||
|
||||
FilterIterator it = view.begin();
|
||||
FilterIterator& result = ++it;
|
||||
ASSERT_SAME_TYPE(FilterIterator&, decltype(++it));
|
||||
assert(&result == &it);
|
||||
assert(base(result.base()) == array.end());
|
||||
}
|
||||
|
||||
// Increment the iterator and it finds another value after begin()
|
||||
{
|
||||
std::array<int, 5> array{99, 1, 99, 1, 99};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), EqualTo{1});
|
||||
|
||||
FilterIterator it = view.begin();
|
||||
++it;
|
||||
assert(base(it.base()) == array.begin() + 3);
|
||||
}
|
||||
|
||||
// Increment advances all the way to the end of the range
|
||||
{
|
||||
std::array<int, 5> array{99, 1, 99, 99, 1};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), EqualTo{1});
|
||||
|
||||
FilterIterator it = view.begin();
|
||||
++it;
|
||||
assert(base(it.base()) == array.begin() + 4);
|
||||
}
|
||||
|
||||
// Increment an iterator multiple times
|
||||
{
|
||||
std::array<int, 10> array{0, 1, 2, 3, 1, 1, 4, 5, 1, 6};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), EqualTo{1});
|
||||
|
||||
FilterIterator it = view.begin();
|
||||
assert(base(it.base()) == array.begin() + 1);
|
||||
++it; assert(base(it.base()) == array.begin() + 4);
|
||||
++it; assert(base(it.base()) == array.begin() + 5);
|
||||
++it; assert(base(it.base()) == array.begin() + 8);
|
||||
++it; assert(base(it.base()) == array.end());
|
||||
}
|
||||
|
||||
// Test with a predicate that takes by non-const reference
|
||||
if constexpr (!IsConst) {
|
||||
std::array<int, 4> array{99, 1, 99, 1};
|
||||
View v{Iterator(array.begin()), Sentinel(Iterator(array.end()))};
|
||||
auto pred = [](int& x) { return x == 1; };
|
||||
auto view = std::ranges::filter_view(std::move(v), pred);
|
||||
auto it = view.begin();
|
||||
assert(base(it.base()) == array.begin() + 1);
|
||||
++it;
|
||||
assert(base(it.base()) == array.begin() + 3);
|
||||
}
|
||||
|
||||
// Make sure we do not make a copy of the predicate when we increment
|
||||
// (we should be passing it to ranges::find_if using std::ref)
|
||||
{
|
||||
bool moved = false, copied = false;
|
||||
std::array<int, 3> array{1, 1, 1};
|
||||
View v{Iterator(array.begin()), Sentinel(Iterator(array.end()))};
|
||||
auto view = std::ranges::filter_view(std::move(v), TrackingPred(&moved, &copied));
|
||||
moved = false;
|
||||
copied = false;
|
||||
auto it = view.begin();
|
||||
++it;
|
||||
it++;
|
||||
assert(!moved);
|
||||
assert(!copied);
|
||||
}
|
||||
|
||||
// Check post-increment for input ranges
|
||||
if constexpr (!IsForwardRange) {
|
||||
std::array<int, 10> array{0, 1, 2, 3, 1, 1, 4, 5, 1, 6};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), EqualTo{1});
|
||||
|
||||
FilterIterator it = view.begin();
|
||||
assert(base(it.base()) == array.begin() + 1);
|
||||
it++; assert(base(it.base()) == array.begin() + 4);
|
||||
it++; assert(base(it.base()) == array.begin() + 5);
|
||||
it++; assert(base(it.base()) == array.begin() + 8);
|
||||
it++; assert(base(it.base()) == array.end());
|
||||
static_assert(std::is_same_v<decltype(it++), void>);
|
||||
}
|
||||
|
||||
// Check post-increment for forward ranges
|
||||
if constexpr (IsForwardRange) {
|
||||
std::array<int, 10> array{0, 1, 2, 3, 1, 1, 4, 5, 1, 6};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), EqualTo{1});
|
||||
|
||||
FilterIterator it = view.begin();
|
||||
FilterIterator result = it++;
|
||||
ASSERT_SAME_TYPE(FilterIterator, decltype(it++));
|
||||
assert(base(result.base()) == array.begin() + 1);
|
||||
assert(base(it.base()) == array.begin() + 4);
|
||||
|
||||
result = it++;
|
||||
assert(base(result.base()) == array.begin() + 4);
|
||||
assert(base(it.base()) == array.begin() + 5);
|
||||
|
||||
result = it++;
|
||||
assert(base(result.base()) == array.begin() + 5);
|
||||
assert(base(it.base()) == array.begin() + 8);
|
||||
|
||||
result = it++;
|
||||
assert(base(result.base()) == array.begin() + 8);
|
||||
assert(base(it.base()) == array.end());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<cpp17_input_iterator<int*>, /* IsForwardRange */ false, /* IsConst */ false>();
|
||||
test<cpp20_input_iterator<int*>, /* IsForwardRange */ false, /* IsConst */ false>();
|
||||
test<forward_iterator<int*>, /* IsForwardRange */ true, /* IsConst */ false>();
|
||||
test<bidirectional_iterator<int*>, /* IsForwardRange */ true, /* IsConst */ false>();
|
||||
test<random_access_iterator<int*>, /* IsForwardRange */ true, /* IsConst */ false>();
|
||||
test<contiguous_iterator<int*>, /* IsForwardRange */ true, /* IsConst */ false>();
|
||||
test<int*, /* IsForwardRange */ true, /* IsConst */ false>();
|
||||
|
||||
test<cpp17_input_iterator<int const*>, /* IsForwardRange */ false, /* IsConst */ true>();
|
||||
test<cpp20_input_iterator<int const*>, /* IsForwardRange */ false, /* IsConst */ true>();
|
||||
test<forward_iterator<int const*>, /* IsForwardRange */ true, /* IsConst */ true>();
|
||||
test<bidirectional_iterator<int const*>, /* IsForwardRange */ true, /* IsConst */ true>();
|
||||
test<random_access_iterator<int const*>, /* IsForwardRange */ true, /* IsConst */ true>();
|
||||
test<contiguous_iterator<int const*>, /* IsForwardRange */ true, /* IsConst */ true>();
|
||||
test<int const*, /* IsForwardRange */ true, /* IsConst */ true>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// friend constexpr range_rvalue_reference_t<V> iter_move(iterator const& i)
|
||||
// noexcept(noexcept(ranges::iter_move(i.current_)));
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class Iterator, bool HasNoexceptIterMove>
|
||||
constexpr void test() {
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
|
||||
auto make_filter_view = [](auto begin, auto end, auto pred) {
|
||||
View view{Iterator(begin), Sentinel(Iterator(end))};
|
||||
return FilterView(std::move(view), pred);
|
||||
};
|
||||
|
||||
{
|
||||
std::array<int, 5> array{0, 1, 2, 3, 4};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), AlwaysTrue{});
|
||||
FilterIterator const it = view.begin();
|
||||
|
||||
int&& result = iter_move(it);
|
||||
static_assert(noexcept(iter_move(it)) == HasNoexceptIterMove);
|
||||
assert(&result == array.begin());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<cpp17_input_iterator<int*>, /* noexcept */ false>();
|
||||
test<cpp20_input_iterator<int*>, /* noexcept */ false>();
|
||||
test<forward_iterator<int*>, /* noexcept */ false>();
|
||||
test<bidirectional_iterator<int*>, /* noexcept */ false>();
|
||||
test<random_access_iterator<int*>, /* noexcept */ false>();
|
||||
test<contiguous_iterator<int*>, /* noexcept */ false>();
|
||||
test<int*, /* noexcept */ true>();
|
||||
test<NoexceptIterMoveInputIterator<true>, /* noexcept */ true>();
|
||||
test<NoexceptIterMoveInputIterator<false>, /* noexcept */ false>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// friend constexpr void iter_swap(iterator const& x, iterator const& y)
|
||||
// noexcept(noexcept(ranges::iter_swap(x.current_, y.current_)))
|
||||
// requires(indirectly_swappable<iterator_t<V>>);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class It>
|
||||
concept has_iter_swap = requires (It it) {
|
||||
std::ranges::iter_swap(it, it);
|
||||
};
|
||||
|
||||
struct IsEven {
|
||||
constexpr bool operator()(int x) const { return x % 2 == 0; }
|
||||
};
|
||||
|
||||
template <class Iterator, bool IsNoexcept>
|
||||
constexpr void test() {
|
||||
using Sentinel = sentinel_wrapper<Iterator>;
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
using FilterView = std::ranges::filter_view<View, IsEven>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
|
||||
auto make_filter_view = [](auto begin, auto end, auto pred) {
|
||||
View view{Iterator(begin), Sentinel(Iterator(end))};
|
||||
return FilterView(std::move(view), pred);
|
||||
};
|
||||
|
||||
{
|
||||
std::array<int, 5> array{1, 2, 1, 4, 1};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), IsEven{});
|
||||
FilterIterator const it1 = view.begin();
|
||||
FilterIterator const it2 = std::ranges::next(view.begin());
|
||||
|
||||
static_assert(std::is_same_v<decltype(iter_swap(it1, it2)), void>);
|
||||
static_assert(noexcept(iter_swap(it1, it2)) == IsNoexcept);
|
||||
|
||||
assert(*it1 == 2 && *it2 == 4); // test the test
|
||||
iter_swap(it1, it2);
|
||||
assert(*it1 == 4);
|
||||
assert(*it2 == 2);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<cpp17_input_iterator<int*>, /* noexcept */ false>();
|
||||
test<cpp20_input_iterator<int*>, /* noexcept */ false>();
|
||||
test<forward_iterator<int*>, /* noexcept */ false>();
|
||||
test<bidirectional_iterator<int*>, /* noexcept */ false>();
|
||||
test<random_access_iterator<int*>, /* noexcept */ false>();
|
||||
test<contiguous_iterator<int*>, /* noexcept */ false>();
|
||||
test<int*, /* noexcept */ true>();
|
||||
test<NoexceptIterSwapInputIterator<true>, /* noexcept */ true>();
|
||||
test<NoexceptIterSwapInputIterator<false>, /* noexcept */ false>();
|
||||
|
||||
// Test that iter_swap requires the underlying iterator to be iter_swappable
|
||||
{
|
||||
using Iterator = int const*;
|
||||
using View = minimal_view<Iterator, Iterator>;
|
||||
using FilterView = std::ranges::filter_view<View, IsEven>;
|
||||
using FilterIterator = std::ranges::iterator_t<FilterView>;
|
||||
static_assert(!std::indirectly_swappable<Iterator>);
|
||||
static_assert(!has_iter_swap<FilterIterator>);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::filter_view::<iterator>::difference_type
|
||||
// std::filter_view::<iterator>::value_type
|
||||
// std::filter_view::<iterator>::iterator_category
|
||||
// std::filter_view::<iterator>::iterator_concept
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <type_traits>
|
||||
#include "test_iterators.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <typename T>
|
||||
concept HasIteratorCategory = requires {
|
||||
typename T::iterator_category;
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
using FilterViewFor = std::ranges::filter_view<
|
||||
minimal_view<Iterator, sentinel_wrapper<Iterator>>,
|
||||
AlwaysTrue
|
||||
>;
|
||||
|
||||
template <class Iterator>
|
||||
using FilterIteratorFor = std::ranges::iterator_t<FilterViewFor<Iterator>>;
|
||||
|
||||
struct ForwardIteratorWithInputCategory {
|
||||
using difference_type = int;
|
||||
using value_type = int;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
ForwardIteratorWithInputCategory();
|
||||
ForwardIteratorWithInputCategory& operator++();
|
||||
ForwardIteratorWithInputCategory operator++(int);
|
||||
int& operator*() const;
|
||||
friend bool operator==(ForwardIteratorWithInputCategory, ForwardIteratorWithInputCategory);
|
||||
};
|
||||
static_assert(std::forward_iterator<ForwardIteratorWithInputCategory>);
|
||||
|
||||
void f() {
|
||||
// Check that value_type is range_value_t and difference_type is range_difference_t
|
||||
{
|
||||
auto test = []<class Iterator> {
|
||||
using FilterView = FilterViewFor<Iterator>;
|
||||
using FilterIterator = FilterIteratorFor<Iterator>;
|
||||
static_assert(std::is_same_v<typename FilterIterator::value_type, std::ranges::range_value_t<FilterView>>);
|
||||
static_assert(std::is_same_v<typename FilterIterator::difference_type, std::ranges::range_difference_t<FilterView>>);
|
||||
};
|
||||
test.operator()<cpp17_input_iterator<int*>>();
|
||||
test.operator()<cpp20_input_iterator<int*>>();
|
||||
test.operator()<forward_iterator<int*>>();
|
||||
test.operator()<bidirectional_iterator<int*>>();
|
||||
test.operator()<random_access_iterator<int*>>();
|
||||
test.operator()<contiguous_iterator<int*>>();
|
||||
test.operator()<int*>();
|
||||
}
|
||||
|
||||
// Check iterator_concept for various categories of ranges
|
||||
{
|
||||
static_assert(std::is_same_v<FilterIteratorFor<cpp17_input_iterator<int*>>::iterator_concept, std::input_iterator_tag>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<cpp20_input_iterator<int*>>::iterator_concept, std::input_iterator_tag>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<ForwardIteratorWithInputCategory>::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<forward_iterator<int*>>::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<bidirectional_iterator<int*>>::iterator_concept, std::bidirectional_iterator_tag>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<random_access_iterator<int*>>::iterator_concept, std::bidirectional_iterator_tag>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<contiguous_iterator<int*>>::iterator_concept, std::bidirectional_iterator_tag>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<int*>::iterator_concept, std::bidirectional_iterator_tag>);
|
||||
}
|
||||
|
||||
// Check iterator_category for various categories of ranges
|
||||
{
|
||||
static_assert(!HasIteratorCategory<FilterIteratorFor<cpp17_input_iterator<int*>>>);
|
||||
static_assert(!HasIteratorCategory<FilterIteratorFor<cpp20_input_iterator<int*>>>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<ForwardIteratorWithInputCategory>::iterator_category, std::input_iterator_tag>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<forward_iterator<int*>>::iterator_category, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<bidirectional_iterator<int*>>::iterator_category, std::bidirectional_iterator_tag>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<random_access_iterator<int*>>::iterator_category, std::bidirectional_iterator_tag>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<contiguous_iterator<int*>>::iterator_category, std::bidirectional_iterator_tag>);
|
||||
static_assert(std::is_same_v<FilterIteratorFor<int*>::iterator_category, std::bidirectional_iterator_tag>);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// Older Clangs don't properly deduce decltype(auto) with a concept constraint
|
||||
// XFAIL: clang-11, clang-12
|
||||
// XFAIL: apple-clang-12, apple-clang-13.0
|
||||
|
||||
// constexpr Pred const& pred() const;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
struct Pred {
|
||||
bool operator()(int) const;
|
||||
int value;
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
Pred pred{42};
|
||||
std::ranges::filter_view<Range, Pred> const view(Range{}, pred);
|
||||
std::same_as<Pred const&> decltype(auto) result = view.pred();
|
||||
assert(result.value == 42);
|
||||
|
||||
// Make sure we're really holding a reference to something inside the view
|
||||
std::same_as<Pred const&> decltype(auto) result2 = view.pred();
|
||||
assert(&result == &result2);
|
||||
}
|
||||
|
||||
// Same, but calling on a non-const view
|
||||
{
|
||||
Pred pred{42};
|
||||
std::ranges::filter_view<Range, Pred> view(Range{}, pred);
|
||||
std::same_as<Pred const&> decltype(auto) result = view.pred();
|
||||
assert(result.value == 42);
|
||||
|
||||
// Make sure we're really holding a reference to something inside the view
|
||||
std::same_as<Pred const&> decltype(auto) result2 = view.pred();
|
||||
assert(&result == &result2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr sentinel_t<V> base() const;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
|
||||
constexpr void test() {
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
|
||||
using FilterSentinel = std::ranges::sentinel_t<FilterView>;
|
||||
|
||||
auto make_filter_view = [](auto begin, auto end, auto pred) {
|
||||
View view{Iterator(begin), Sentinel(Iterator(end))};
|
||||
return FilterView(std::move(view), pred);
|
||||
};
|
||||
|
||||
std::array<int, 5> array{0, 1, 2, 3, 4};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), AlwaysTrue{});
|
||||
|
||||
FilterSentinel const sent = view.end();
|
||||
std::same_as<Sentinel> decltype(auto) result = sent.base();
|
||||
assert(base(base(result)) == array.end());
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<cpp17_input_iterator<int*>>();
|
||||
test<cpp20_input_iterator<int*>>();
|
||||
test<forward_iterator<int*>>();
|
||||
test<bidirectional_iterator<int*>>();
|
||||
test<random_access_iterator<int*>>();
|
||||
test<contiguous_iterator<int*>>();
|
||||
test<int*>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// friend constexpr bool operator==(iterator const&, sentinel const&);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
|
||||
constexpr void test() {
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
|
||||
std::array<int, 5> array{0, 1, 2, 3, 4};
|
||||
|
||||
{
|
||||
View v(Iterator(array.begin()), Sentinel(Iterator(array.end())));
|
||||
std::ranges::filter_view view(std::move(v), AlwaysTrue{});
|
||||
auto const it = view.begin();
|
||||
auto const sent = view.end();
|
||||
std::same_as<bool> decltype(auto) result = (it == sent);
|
||||
assert(!result);
|
||||
}
|
||||
{
|
||||
View v(Iterator(array.begin()), Sentinel(Iterator(array.end())));
|
||||
std::ranges::filter_view view(std::move(v), [](auto) { return false; });
|
||||
auto const it = view.begin();
|
||||
auto const sent = view.end();
|
||||
std::same_as<bool> decltype(auto) result = (it == sent);
|
||||
assert(result);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<cpp17_input_iterator<int*>>();
|
||||
test<cpp20_input_iterator<int*>>();
|
||||
test<forward_iterator<int*>>();
|
||||
test<bidirectional_iterator<int*>>();
|
||||
test<random_access_iterator<int*>>();
|
||||
test<contiguous_iterator<int*>>();
|
||||
test<int*>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// filter_view<V>::<sentinel>() = default;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include "test_iterators.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
|
||||
constexpr void test() {
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
|
||||
using FilterSentinel = std::ranges::sentinel_t<FilterView>;
|
||||
FilterSentinel sent1{};
|
||||
FilterSentinel sent2;
|
||||
assert(base(base(sent1.base())) == base(base(sent2.base())));
|
||||
static_assert(noexcept(FilterSentinel()));
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<cpp17_input_iterator<int*>>();
|
||||
test<cpp20_input_iterator<int*>>();
|
||||
test<forward_iterator<int*>>();
|
||||
test<bidirectional_iterator<int*>>();
|
||||
test<random_access_iterator<int*>>();
|
||||
test<contiguous_iterator<int*>>();
|
||||
test<int*>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// constexpr explicit sentinel(filter_view&);
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "test_iterators.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
|
||||
constexpr void test() {
|
||||
using View = minimal_view<Iterator, Sentinel>;
|
||||
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
|
||||
using FilterSentinel = std::ranges::sentinel_t<FilterView>;
|
||||
|
||||
auto make_filter_view = [](auto begin, auto end, auto pred) {
|
||||
View view{Iterator(begin), Sentinel(Iterator(end))};
|
||||
return FilterView(std::move(view), pred);
|
||||
};
|
||||
|
||||
std::array<int, 5> array{0, 1, 2, 3, 4};
|
||||
FilterView view = make_filter_view(array.begin(), array.end(), AlwaysTrue{});
|
||||
|
||||
FilterSentinel sent(view);
|
||||
assert(base(base(sent.base())) == base(base(view.end().base())));
|
||||
|
||||
static_assert(!std::is_constructible_v<FilterSentinel, FilterView const&>);
|
||||
static_assert(!std::is_constructible_v<FilterSentinel, FilterView>);
|
||||
static_assert( std::is_constructible_v<FilterSentinel, FilterView&> &&
|
||||
!std::is_convertible_v<FilterView&, FilterSentinel>);
|
||||
}
|
||||
|
||||
constexpr bool tests() {
|
||||
test<cpp17_input_iterator<int*>>();
|
||||
test<cpp20_input_iterator<int*>>();
|
||||
test<forward_iterator<int*>>();
|
||||
test<bidirectional_iterator<int*>>();
|
||||
test<random_access_iterator<int*>>();
|
||||
test<contiguous_iterator<int*>>();
|
||||
test<int*>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
tests();
|
||||
static_assert(tests());
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_FILTER_TYPES_H
|
||||
#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_FILTER_TYPES_H
|
||||
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
struct TrackInitialization {
|
||||
constexpr explicit TrackInitialization(bool* moved, bool* copied) : moved_(moved), copied_(copied) { }
|
||||
constexpr TrackInitialization(TrackInitialization const& other) : moved_(other.moved_), copied_(other.copied_) {
|
||||
*copied_ = true;
|
||||
}
|
||||
constexpr TrackInitialization(TrackInitialization&& other) : moved_(other.moved_), copied_(other.copied_) {
|
||||
*moved_ = true;
|
||||
}
|
||||
TrackInitialization& operator=(TrackInitialization const&) = default;
|
||||
TrackInitialization& operator=(TrackInitialization&&) = default;
|
||||
bool* moved_;
|
||||
bool* copied_;
|
||||
};
|
||||
|
||||
struct AlwaysTrue {
|
||||
template <typename T>
|
||||
constexpr bool operator()(T const&) const { return true; }
|
||||
};
|
||||
|
||||
template <class Iterator, class Sentinel>
|
||||
struct minimal_view : std::ranges::view_base {
|
||||
constexpr explicit minimal_view(Iterator it, Sentinel sent)
|
||||
: it_(base(std::move(it)))
|
||||
, sent_(base(std::move(sent)))
|
||||
{ }
|
||||
|
||||
minimal_view(minimal_view&&) = default;
|
||||
minimal_view& operator=(minimal_view&&) = default;
|
||||
|
||||
constexpr Iterator begin() const { return Iterator(it_); }
|
||||
constexpr Sentinel end() const { return Sentinel(sent_); }
|
||||
|
||||
private:
|
||||
decltype(base(std::declval<Iterator>())) it_;
|
||||
decltype(base(std::declval<Sentinel>())) sent_;
|
||||
};
|
||||
|
||||
template <bool IsNoexcept>
|
||||
class NoexceptIterMoveInputIterator {
|
||||
int *it_;
|
||||
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = int;
|
||||
using difference_type = typename std::iterator_traits<int *>::difference_type;
|
||||
using pointer = int*;
|
||||
using reference = int&;
|
||||
|
||||
NoexceptIterMoveInputIterator() = default;
|
||||
explicit constexpr NoexceptIterMoveInputIterator(int *it) : it_(it) {}
|
||||
|
||||
friend constexpr decltype(auto) iter_move(const NoexceptIterMoveInputIterator& it) noexcept(IsNoexcept) {
|
||||
return std::ranges::iter_move(it.it_);
|
||||
}
|
||||
|
||||
friend constexpr int* base(const NoexceptIterMoveInputIterator& i) { return i.it_; }
|
||||
|
||||
constexpr reference operator*() const { return *it_; }
|
||||
constexpr NoexceptIterMoveInputIterator& operator++() {++it_; return *this;}
|
||||
constexpr NoexceptIterMoveInputIterator operator++(int)
|
||||
{ NoexceptIterMoveInputIterator tmp(*this); ++(*this); return tmp; }
|
||||
};
|
||||
|
||||
template <bool IsNoexcept>
|
||||
class NoexceptIterSwapInputIterator {
|
||||
int *it_;
|
||||
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = int;
|
||||
using difference_type = typename std::iterator_traits<int *>::difference_type;
|
||||
using pointer = int*;
|
||||
using reference = int&;
|
||||
|
||||
NoexceptIterSwapInputIterator() = default;
|
||||
explicit constexpr NoexceptIterSwapInputIterator(int *it) : it_(it) {}
|
||||
|
||||
friend constexpr void iter_swap(const NoexceptIterSwapInputIterator& a, const NoexceptIterSwapInputIterator& b) noexcept(IsNoexcept) {
|
||||
return std::ranges::iter_swap(a.it_, b.it_);
|
||||
}
|
||||
|
||||
friend constexpr int* base(const NoexceptIterSwapInputIterator& i) { return i.it_; }
|
||||
|
||||
constexpr reference operator*() const { return *it_; }
|
||||
constexpr NoexceptIterSwapInputIterator& operator++() {++it_; return *this;}
|
||||
constexpr NoexceptIterSwapInputIterator operator++(int)
|
||||
{ NoexceptIterSwapInputIterator tmp(*this); ++(*this); return tmp; }
|
||||
};
|
||||
|
||||
#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_FILTER_TYPES_H
|
Loading…
Reference in New Issue