[libcxx][ranges] Add `ranges::transform_view`.

Reviewed By: cjdb, ldionne, #libc

Differential Revision: https://reviews.llvm.org/D103056
This commit is contained in:
zoecarver 2021-07-09 10:12:16 -07:00
parent 0849427fae
commit 0e09a41b41
25 changed files with 1547 additions and 1 deletions

View File

@ -137,7 +137,7 @@ Section,Description,Dependencies,Assignee,Complete
`[range.all] <http://wg21.link/range.all>`_,`view::all <https://llvm.org/D102028>`_,"[range.subrange], [range.view.ref]",Zoe Carver,In progress
`[range.view.ref] <http://wg21.link/range.view>`_,`ref-view <https://llvm.org/D102020>`_,[view.interface],Zoe Carver,In progress
`[range.filter] <http://wg21.link/range.filter>`_,filter_view,[range.all],Louis Dionne,Not started
`[range.transform] <http://wg21.link/range.transform>`_,`transform_view <https://llvm.org/D103056>`_,[range.all],Zoe Carver,In progress
`[range.transform] <http://wg21.link/range.transform>`_,`transform_view <https://llvm.org/D103056>`_,[range.all],Zoe Carver,
`[range.iota] <http://wg21.link/range.iota>`_,iota_view,[range.all],Louis Dionne,Not started
`[range.take] <http://wg21.link/range.take>`_,take_view,[range.all],Zoe Carver,Not started
`[range.join] <http://wg21.link/range.join>`_,join_view,[range.all],Christopher Di Bella,Not started

1 Section Description Dependencies Assignee Complete
137
138
139
140
141
142
143

View File

@ -194,6 +194,7 @@ set(files
__ranges/ref_view.h
__ranges/size.h
__ranges/subrange.h
__ranges/transform_view.h
__ranges/view_interface.h
__split_buffer
__std_stream

View File

@ -12,6 +12,7 @@
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__iterator/concepts.h>
#include <__iterator/next.h>
#include <__ranges/access.h>
#include <__ranges/view_interface.h>
#include <__ranges/all.h>

View File

@ -0,0 +1,363 @@
// -*- 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_TRANSFORM_VIEW_H
#define _LIBCPP___RANGES_TRANSFORM_VIEW_H
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__iterator/concepts.h>
#include <__iterator/iter_swap.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/copyable_box.h>
#include <__ranges/empty.h>
#include <__ranges/view_interface.h>
#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if !defined(_LIBCPP_HAS_NO_RANGES)
namespace ranges {
template<class _View, class _Fn>
concept __transform_view_constraints =
view<_View> && is_object_v<_Fn> &&
regular_invocable<_Fn&, range_reference_t<_View>> &&
__referenceable<invoke_result_t<_Fn&, range_reference_t<_View>>>;
template<input_range _View, copy_constructible _Fn>
requires __transform_view_constraints<_View, _Fn>
class transform_view : public view_interface<transform_view<_View, _Fn>> {
template<bool> class __iterator;
template<bool> class __sentinel;
[[no_unique_address]] __copyable_box<_Fn> __func_;
[[no_unique_address]] _View __base_ = _View();
public:
transform_view()
requires default_initializable<_View> && default_initializable<_Fn> = default;
constexpr transform_view(_View __base, _Fn __func)
: __func_(_VSTD::in_place, _VSTD::move(__func)), __base_(_VSTD::move(__base)) {}
constexpr _View base() const& requires copy_constructible<_View> { return __base_; }
constexpr _View base() && { return _VSTD::move(__base_); }
constexpr __iterator<false> begin() {
return __iterator<false>{*this, ranges::begin(__base_)};
}
constexpr __iterator<true> begin() const
requires range<const _View> &&
regular_invocable<const _Fn&, range_reference_t<const _View>>
{
return __iterator<true>(*this, ranges::begin(__base_));
}
constexpr __sentinel<false> end() {
return __sentinel<false>(ranges::end(__base_));
}
constexpr __iterator<false> end()
requires common_range<_View>
{
return __iterator<false>(*this, ranges::end(__base_));
}
constexpr __sentinel<true> end() const
requires range<const _View> &&
regular_invocable<const _Fn&, range_reference_t<const _View>>
{
return __sentinel<true>(ranges::end(__base_));
}
constexpr __iterator<true> end() const
requires common_range<const _View> &&
regular_invocable<const _Fn&, range_reference_t<const _View>>
{
return __iterator<true>(*this, ranges::end(__base_));
}
constexpr auto size() requires sized_range<_View> { return ranges::size(__base_); }
constexpr auto size() const requires sized_range<const _View> { return ranges::size(__base_); }
};
// TODO: replace the decltype with all_t when that's implemented.
template<class _Range, class _Fn>
transform_view(_Range&&, _Fn)
-> transform_view<decltype(views::all(std::declval<_Range>())), _Fn>;
template<class _View>
struct __transform_view_iterator_concept { using type = input_iterator_tag; };
template<random_access_range _View>
struct __transform_view_iterator_concept<_View> { using type = random_access_iterator_tag; };
template<bidirectional_range _View>
struct __transform_view_iterator_concept<_View> { using type = bidirectional_iterator_tag; };
template<forward_range _View>
struct __transform_view_iterator_concept<_View> { using type = forward_iterator_tag; };
template<class, class>
struct __transform_view_iterator_category_base {};
template<forward_range _View, class _Fn>
struct __transform_view_iterator_category_base<_View, _Fn> {
using _Cat = typename iterator_traits<iterator_t<_View>>::iterator_category;
using iterator_category = conditional_t<
is_lvalue_reference_v<invoke_result_t<_Fn&, range_reference_t<_View>>>,
conditional_t<
derived_from<_Cat, contiguous_iterator_tag>,
random_access_iterator_tag,
_Cat
>,
input_iterator_tag
>;
};
template<input_range _View, copy_constructible _Fn>
requires __transform_view_constraints<_View, _Fn>
template<bool _Const>
class transform_view<_View, _Fn>::__iterator
: public __transform_view_iterator_category_base<_View, _Fn> {
using _Parent = __maybe_const<_Const, transform_view>;
using _Base = __maybe_const<_Const, _View>;
_Parent *__parent_ = nullptr;
template<bool>
friend class transform_view<_View, _Fn>::__iterator;
template<bool>
friend class transform_view<_View, _Fn>::__sentinel;
public:
iterator_t<_Base> __current_ = iterator_t<_Base>();
using iterator_concept = typename __transform_view_iterator_concept<_View>::type;
using value_type = remove_cvref_t<invoke_result_t<_Fn&, range_reference_t<_Base>>>;
using difference_type = range_difference_t<_Base>;
__iterator() requires default_initializable<iterator_t<_Base>> = default;
constexpr __iterator(_Parent& __parent, iterator_t<_Base> __current)
: __parent_(_VSTD::addressof(__parent)), __current_(_VSTD::move(__current)) {}
// Note: `__i` should always be `__iterator<false>`, but directly using
// `__iterator<false>` is ill-formed when `_Const` is false
// (see http://wg21.link/class.copy.ctor#5).
constexpr __iterator(__iterator<!_Const> __i)
requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
: __parent_(__i.__parent_), __current_(_VSTD::move(__i.__current_)) {}
constexpr iterator_t<_Base> base() const&
requires copyable<iterator_t<_Base>>
{
return __current_;
}
constexpr iterator_t<_Base> base() && {
return _VSTD::move(__current_);
}
constexpr decltype(auto) operator*() const
noexcept(noexcept(_VSTD::invoke(*__parent_->__func_, *__current_)))
{
return _VSTD::invoke(*__parent_->__func_, *__current_);
}
constexpr __iterator& operator++() {
++__current_;
return *this;
}
constexpr void operator++(int) { ++__current_; }
constexpr __iterator operator++(int)
requires forward_range<_Base>
{
auto __tmp = *this;
++*this;
return __tmp;
}
constexpr __iterator& operator--()
requires bidirectional_range<_Base>
{
--__current_;
return *this;
}
constexpr __iterator operator--(int)
requires bidirectional_range<_Base>
{
auto __tmp = *this;
--*this;
return __tmp;
}
constexpr __iterator& operator+=(difference_type __n)
requires random_access_range<_Base>
{
__current_ += __n;
return *this;
}
constexpr __iterator& operator-=(difference_type __n)
requires random_access_range<_Base>
{
__current_ -= __n;
return *this;
}
constexpr decltype(auto) operator[](difference_type __n) const
noexcept(noexcept(_VSTD::invoke(*__parent_->__func_, __current_[__n])))
requires random_access_range<_Base>
{
return _VSTD::invoke(*__parent_->__func_, __current_[__n]);
}
friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
requires equality_comparable<iterator_t<_Base>>
{
return __x.__current_ == __y.__current_;
}
friend constexpr bool operator<(const __iterator& __x, const __iterator& __y)
requires random_access_range<_Base>
{
return __x.__current_ < __y.__current_;
}
friend constexpr bool operator>(const __iterator& __x, const __iterator& __y)
requires random_access_range<_Base>
{
return __x.__current_ > __y.__current_;
}
friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y)
requires random_access_range<_Base>
{
return __x.__current_ <= __y.__current_;
}
friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y)
requires random_access_range<_Base>
{
return __x.__current_ >= __y.__current_;
}
// TODO: Fix this as soon as soon as three_way_comparable is implemented.
// friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y)
// requires random_access_range<_Base> && three_way_comparable<iterator_t<_Base>>
// {
// return __x.__current_ <=> __y.__current_;
// }
friend constexpr __iterator operator+(__iterator __i, difference_type __n)
requires random_access_range<_Base>
{
return __iterator{*__i.__parent_, __i.__current_ + __n};
}
friend constexpr __iterator operator+(difference_type __n, __iterator __i)
requires random_access_range<_Base>
{
return __iterator{*__i.__parent_, __i.__current_ + __n};
}
friend constexpr __iterator operator-(__iterator __i, difference_type __n)
requires random_access_range<_Base>
{
return __iterator{*__i.__parent_, __i.__current_ - __n};
}
friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y)
requires sized_sentinel_for<iterator_t<_Base>, iterator_t<_Base>>
{
return __x.__current_ - __y.__current_;
}
friend constexpr decltype(auto) iter_move(const __iterator& __i)
noexcept(noexcept(*__i))
{
if constexpr (is_lvalue_reference_v<decltype(*__i)>)
return _VSTD::move(*__i);
else
return *__i;
}
};
template<input_range _View, copy_constructible _Fn>
requires __transform_view_constraints<_View, _Fn>
template<bool _Const>
class transform_view<_View, _Fn>::__sentinel {
using _Parent = __maybe_const<_Const, transform_view>;
using _Base = __maybe_const<_Const, _View>;
sentinel_t<_Base> __end_ = sentinel_t<_Base>();
template<bool>
friend class transform_view<_View, _Fn>::__iterator;
template<bool>
friend class transform_view<_View, _Fn>::__sentinel;
public:
__sentinel() = default;
constexpr explicit __sentinel(sentinel_t<_Base> __end_) : __end_(__end_) {}
// Note: `__i` should always be `__sentinel<false>`, but directly using
// `__sentinel<false>` is ill-formed when `_Const` is false
// (see http://wg21.link/class.copy.ctor#5).
constexpr __sentinel(__sentinel<!_Const> __i)
requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
: __end_(_VSTD::move(__i.__end_)) {}
constexpr sentinel_t<_Base> base() const { return __end_; }
template<bool _OtherConst>
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
return __x.__current_ == __y.__end_;
}
template<bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
return __x.__current_ - __y.__end_;
}
template<bool _OtherConst>
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>>
operator-(const __sentinel& __x, const __iterator<_OtherConst>& __y) {
return __x.__end_ - __y.__current_;
}
};
} // namespace ranges
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___RANGES_TRANSFORM_VIEW_H

View File

@ -101,6 +101,14 @@ namespace std::ranges {
template<class T>
inline constexpr bool enable_borrowed_range<drop_view<T>> = enable_borrowed_range<T>;
// [range.transform], transform view
template<input_range V, copy_constructible F>
requires view<V> && is_object_v<F> &&
regular_invocable<F&, range_reference_t<V>> &&
can-reference<invoke_result_t<F&, range_reference_t<V>>>
class transform_view;
}
*/
@ -118,6 +126,7 @@ namespace std::ranges {
#include <__ranges/ref_view.h>
#include <__ranges/size.h>
#include <__ranges/subrange.h>
#include <__ranges/transform_view.h>
#include <__ranges/view_interface.h>
#include <compare> // Required by the standard.
#include <initializer_list> // Required by the standard.

View File

@ -4474,6 +4474,11 @@ using _IsCharLikeType = _And<is_standard_layout<_CharT>, is_trivial<_CharT> >;
template<class _Tp>
using __make_const_lvalue_ref = const typename remove_reference<_Tp>::type&;
#if _LIBCPP_STD_VER > 17
template<bool _Const, class _Tp>
using __maybe_const = conditional_t<_Const, const _Tp, _Tp>;
#endif // _LIBCPP_STD_VER > 17
_LIBCPP_END_NAMESPACE_STD
#if _LIBCPP_STD_VER > 14

View File

@ -0,0 +1,59 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
// constexpr V base() const& requires copy_constructible<V>
// constexpr V base() &&
#include <ranges>
#include "test_macros.h"
#include "types.h"
constexpr bool test() {
{
std::ranges::transform_view<ContiguousView, Increment> transformView;
ContiguousView base = std::move(transformView).base();
ASSERT_SAME_TYPE(ContiguousView, decltype(std::move(transformView).base()));
assert(std::ranges::begin(base) == globalBuff);
}
{
std::ranges::transform_view<CopyableView, Increment> transformView;
CopyableView base1 = transformView.base();
ASSERT_SAME_TYPE(CopyableView, decltype(transformView.base()));
assert(std::ranges::begin(base1) == globalBuff);
CopyableView base2 = std::move(transformView).base();
ASSERT_SAME_TYPE(CopyableView, decltype(std::move(transformView).base()));
assert(std::ranges::begin(base2) == globalBuff);
}
{
const std::ranges::transform_view<CopyableView, Increment> transformView;
const CopyableView base1 = transformView.base();
ASSERT_SAME_TYPE(CopyableView, decltype(transformView.base()));
assert(std::ranges::begin(base1) == globalBuff);
const CopyableView base2 = std::move(transformView).base();
ASSERT_SAME_TYPE(CopyableView, decltype(std::move(transformView).base()));
assert(std::ranges::begin(base2) == globalBuff);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -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-no-concepts
// UNSUPPORTED: gcc-10
// constexpr iterator<false> begin();
// constexpr iterator<true> begin() const
// requires range<const V> &&
// regular_invocable<const F&, range_reference_t<const V>>;
#include <ranges>
#include "test_macros.h"
#include "types.h"
template<class T>
concept BeginInvocable = requires(T t) { t.begin(); };
constexpr bool test() {
int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
{
std::ranges::transform_view transformView(ContiguousView{buff}, Increment{});
assert(transformView.begin().base() == buff);
assert(*transformView.begin() == 1);
}
{
std::ranges::transform_view transformView(ForwardView{buff}, Increment{});
assert(transformView.begin().base().base() == buff);
assert(*transformView.begin() == 1);
}
{
std::ranges::transform_view transformView(InputView{buff}, Increment{});
assert(transformView.begin().base().base() == buff);
assert(*transformView.begin() == 1);
}
{
const std::ranges::transform_view transformView(ContiguousView{buff}, IncrementConst{});
assert(*transformView.begin() == 1);
}
static_assert(!BeginInvocable<const std::ranges::transform_view<ContiguousView, Increment>>);
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,25 @@
//===----------------------------------------------------------------------===//
//
// 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-no-concepts
// UNSUPPORTED: gcc-10
// CTAD tests.
#include <ranges>
#include "test_macros.h"
#include "types.h"
static_assert(std::same_as<decltype(std::ranges::transform_view(InputView(), Increment())),
std::ranges::transform_view<InputView, Increment>>);
static_assert(std::same_as<decltype(std::ranges::transform_view(std::declval<ForwardRange&>(), Increment())),
std::ranges::transform_view<std::ranges::ref_view<ForwardRange>, Increment>>);
static_assert(std::same_as<decltype(std::ranges::transform_view(BorrowableRange(), Increment())),
std::ranges::transform_view<std::ranges::subrange<int*>, Increment>>);

View File

@ -0,0 +1,74 @@
//===----------------------------------------------------------------------===//
//
// 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-no-concepts
// UNSUPPORTED: gcc-10
// constexpr sentinel<false> end();
// constexpr iterator<false> end() requires common_range<V>;
// constexpr sentinel<true> end() const
// requires range<const V> &&
// regular_invocable<const F&, range_reference_t<const V>>;
// constexpr iterator<true> end() const
// requires common_range<const V> &&
// regular_invocable<const F&, range_reference_t<const V>>;
#include <ranges>
#include "test_macros.h"
#include "types.h"
template<class T>
concept EndInvocable = requires(T t) { t.end(); };
template<class T>
concept EndIsIter = requires(T t) { ++t.end(); };
constexpr bool test() {
{
std::ranges::transform_view transformView(ContiguousView{}, Increment{});
assert(transformView.end().base() == globalBuff + 8);
}
{
std::ranges::transform_view transformView(ForwardView{}, Increment{});
assert(transformView.end().base().base() == globalBuff + 8);
}
{
std::ranges::transform_view transformView(InputView{}, Increment{});
assert(transformView.end().base() == globalBuff + 8);
}
{
const std::ranges::transform_view transformView(ContiguousView{}, IncrementConst{});
assert(transformView.end().base() == globalBuff + 8);
}
static_assert(!EndInvocable<const std::ranges::transform_view<ContiguousView, Increment>>);
static_assert( EndInvocable< std::ranges::transform_view<ContiguousView, Increment>>);
static_assert( EndInvocable<const std::ranges::transform_view<ContiguousView, IncrementConst>>);
static_assert(!EndInvocable<const std::ranges::transform_view<InputView, Increment>>);
static_assert( EndInvocable< std::ranges::transform_view<InputView, Increment>>);
static_assert( EndInvocable<const std::ranges::transform_view<InputView, IncrementConst>>);
static_assert(!EndIsIter<const std::ranges::transform_view<InputView, IncrementConst>>);
static_assert(!EndIsIter< std::ranges::transform_view<InputView, Increment>>);
static_assert( EndIsIter<const std::ranges::transform_view<ContiguousView, IncrementConst>>);
static_assert( EndIsIter< std::ranges::transform_view<ContiguousView, Increment>>);
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,75 @@
//===----------------------------------------------------------------------===//
//
// 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-no-concepts
// UNSUPPORTED: gcc-10
// Some basic examples of how transform_view might be used in the wild. This is a general
// collection of sample algorithms and functions that try to mock general usage of
// this view.
#include <ranges>
#include <cctype>
#include <functional>
#include <list>
#include <numeric>
#include <string>
#include <vector>
#include <cassert>
#include "test_macros.h"
#include "test_iterators.h"
#include "types.h"
template<std::ranges::range R>
auto toUpper(R range) {
return std::ranges::transform_view(range, [](char c) { return std::toupper(c); });
}
unsigned badRandom() { return 42; }
template<std::ranges::range R, class Fn = std::plus<std::iter_value_t<R>>>
auto withRandom(R&& range, Fn func = Fn()) {
return std::ranges::transform_view(range, std::bind_front(func, badRandom()));
}
template<class E1, class E2, size_t N, class Join = std::plus<E1>>
auto joinArrays(E1 (&a)[N], E2 (&b)[N], Join join = Join()) {
return std::ranges::transform_view(a, [&a, &b, join](auto& x) {
auto idx = (&x) - a;
return join(x, b[idx]);
});
}
int main(int, char**) {
{
std::vector vec = {1, 2, 3, 4};
auto sortOfRandom = withRandom(vec);
std::vector check = {43, 44, 45, 46};
assert(std::equal(sortOfRandom.begin(), sortOfRandom.end(), check.begin(), check.end()));
}
{
int a[4] = {1, 2, 3, 4};
int b[4] = {4, 3, 2, 1};
auto out = joinArrays(a, b);
int check[4] = {5, 5, 5, 5};
assert(std::equal(out.begin(), out.end(), check));
}
{
std::string_view str = "Hello, World.";
auto upp = toUpper(str);
std::string_view check = "HELLO, WORLD.";
assert(std::equal(upp.begin(), upp.end(), check.begin(), check.end()));
}
return 0;
}

View File

@ -0,0 +1,48 @@
//===----------------------------------------------------------------------===//
//
// 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-no-concepts
// UNSUPPORTED: gcc-10
// transform_view::<iterator>::operator{++,--,+=,-=}
#include <ranges>
#include "test_macros.h"
#include "../types.h"
constexpr bool test() {
std::ranges::transform_view<ContiguousView, Increment> transformView;
auto iter = std::move(transformView).begin();
assert((++iter).base() == globalBuff + 1);
assert((iter++).base() == globalBuff + 1);
assert(iter.base() == globalBuff + 2);
assert((--iter).base() == globalBuff + 1);
assert((iter--).base() == globalBuff + 1);
assert(iter.base() == globalBuff);
// Check that decltype(InputIter++) == void.
ASSERT_SAME_TYPE(decltype(
std::declval<std::ranges::iterator_t<std::ranges::transform_view<InputView, Increment>>>()++),
void);
assert((iter += 4).base() == globalBuff + 4);
assert((iter -= 3).base() == globalBuff + 1);
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -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-no-concepts
// UNSUPPORTED: gcc-10
// transform_view::<iterator>::base
#include <ranges>
#include "test_macros.h"
#include "../types.h"
template<class V, class F>
concept BaseInvocable = requires(std::ranges::iterator_t<std::ranges::transform_view<V, F>> iter) {
iter.base();
};
constexpr bool test() {
{
std::ranges::transform_view<ContiguousView, Increment> transformView;
auto iter = std::move(transformView).begin();
ASSERT_SAME_TYPE(int*, decltype(iter.base()));
assert(iter.base() == globalBuff);
ASSERT_SAME_TYPE(int*, decltype(std::move(iter).base()));
assert(std::move(iter).base() == globalBuff);
}
{
std::ranges::transform_view<InputView, Increment> transformView;
auto iter = transformView.begin();
assert(std::move(iter).base() == globalBuff);
ASSERT_SAME_TYPE(cpp20_input_iterator<int *>, decltype(std::move(iter).base()));
}
static_assert(!BaseInvocable<InputView, Increment>);
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,67 @@
//===----------------------------------------------------------------------===//
//
// 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-no-concepts
// UNSUPPORTED: gcc-10
// transform_view::<iterator>::operator{<,>,<=,>=}
#include <ranges>
#include <compare>
#include "test_macros.h"
#include "../types.h"
constexpr bool test() {
{
std::ranges::transform_view<ContiguousView, Increment> transformView1;
auto iter1 = std::move(transformView1).begin();
std::ranges::transform_view<ContiguousView, Increment> transformView2;
auto iter2 = std::move(transformView2).begin();
assert(iter1 == iter2);
assert(iter1 + 1 != iter2);
assert(iter1 + 1 == iter2 + 1);
assert(iter1 < iter1 + 1);
assert(iter1 + 1 > iter1);
assert(iter1 <= iter1 + 1);
assert(iter1 <= iter2);
assert(iter1 + 1 >= iter2);
assert(iter1 >= iter2);
}
// TODO: when three_way_comparable is implemented and std::is_eq is implemented,
// uncomment this.
// {
// std::ranges::transform_view<ThreeWayCompView, Increment> transformView1;
// auto iter1 = transformView1.begin();
// std::ranges::transform_view<ThreeWayCompView, Increment> transformView2;
// auto iter2 = transformView2.begin();
//
// assert(std::is_eq(iter1 <=> iter2));
// assert(std::is_lteq(iter1 <=> iter2));
// ++iter2;
// assert(std::is_neq(iter1 <=> iter2));
// assert(std::is_lt(iter1 <=> iter2));
// assert(std::is_gt(iter2 <=> iter1));
// assert(std::is_gteq(iter2 <=> iter1));
//
// static_assert( std::three_way_comparable<std::iterator_t<std::ranges::transform_view<ThreeWayCompView, Increment>>>);
// static_assert(!std::three_way_comparable<std::iterator_t<std::ranges::transform_view<ContiguousView, Increment>>>);
// }
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,79 @@
//===----------------------------------------------------------------------===//
//
// 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-no-concepts
// UNSUPPORTED: gcc-10
// transform_view::<iterator>::transform_view::<iterator>();
#include <ranges>
#include "test_macros.h"
#include "../types.h"
struct NoDefaultInit {
typedef std::random_access_iterator_tag iterator_category;
typedef int value_type;
typedef std::ptrdiff_t difference_type;
typedef int* pointer;
typedef int& reference;
typedef NoDefaultInit self;
NoDefaultInit(int*);
reference operator*() const;
pointer operator->() const;
auto operator<=>(const self&) const = default;
bool operator==(int *) const;
self& operator++();
self operator++(int);
self& operator--();
self operator--(int);
self& operator+=(difference_type n);
self operator+(difference_type n) const;
friend self operator+(difference_type n, self x);
self& operator-=(difference_type n);
self operator-(difference_type n) const;
difference_type operator-(const self&) const;
reference operator[](difference_type n) const;
};
struct IterNoDefaultInitView : std::ranges::view_base {
NoDefaultInit begin() const;
int *end() const;
NoDefaultInit begin();
int *end();
};
constexpr bool test() {
std::ranges::transform_view<ContiguousView, IncrementConst> transformView;
auto iter = std::move(transformView).begin();
std::ranges::iterator_t<std::ranges::transform_view<ContiguousView, IncrementConst>> i2(iter);
(void)i2;
std::ranges::iterator_t<const std::ranges::transform_view<ContiguousView, IncrementConst>> constIter(iter);
(void)constIter;
static_assert( std::default_initializable<std::ranges::iterator_t<std::ranges::transform_view<ContiguousView, IncrementConst>>>);
static_assert(!std::default_initializable<std::ranges::iterator_t<std::ranges::transform_view<IterNoDefaultInitView, IncrementConst>>>);
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,44 @@
//===----------------------------------------------------------------------===//
//
// 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-no-concepts
// UNSUPPORTED: gcc-10
// transform_view::<iterator>::operator*
#include <ranges>
#include "test_macros.h"
#include "../types.h"
int main(int, char**) {
int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
{
std::ranges::transform_view transformView(ContiguousView{buff}, Increment{});
assert(*transformView.begin() == 1);
}
static_assert(!noexcept(
*std::declval<std::ranges::iterator_t<std::ranges::transform_view<ContiguousView, Increment>>>()));
static_assert( noexcept(
*std::declval<std::ranges::iterator_t<std::ranges::transform_view<ContiguousView, IncrementNoexcept>>>()));
ASSERT_SAME_TYPE(
int,
decltype(*std::declval<std::ranges::transform_view<RandomAccessView, Increment>>().begin()));
ASSERT_SAME_TYPE(
int&,
decltype(*std::declval<std::ranges::transform_view<RandomAccessView, IncrementRef>>().begin()));
ASSERT_SAME_TYPE(
int&&,
decltype(*std::declval<std::ranges::transform_view<RandomAccessView, IncrementRvalueRef>>().begin()));
return 0;
}

View File

@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
// transform_view::<iterator>::operator[]
#include <ranges>
#include "test_macros.h"
#include "../types.h"
constexpr bool test() {
int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
{
std::ranges::transform_view transformView(ContiguousView{buff}, Increment{});
auto iter = transformView.begin();
static_assert(!noexcept(std::ranges::iter_move(iter)));
assert(std::ranges::iter_move(iter) == 1);
assert(std::ranges::iter_move(iter + 2) == 3);
ASSERT_SAME_TYPE(int, decltype(std::ranges::iter_move(iter)));
ASSERT_SAME_TYPE(int, decltype(std::ranges::iter_move(std::move(iter))));
}
{
static_assert( noexcept(std::ranges::iter_move(
std::declval<std::ranges::iterator_t<std::ranges::transform_view<ContiguousView, IncrementNoexcept>>&>())));
static_assert(!noexcept(std::ranges::iter_move(
std::declval<std::ranges::iterator_t<std::ranges::transform_view<ContiguousView, Increment>>&>())));
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,41 @@
//===----------------------------------------------------------------------===//
//
// 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-no-concepts
// UNSUPPORTED: gcc-10
// transform_view::<iterator>::operator{+,-}
#include <ranges>
#include "test_macros.h"
#include "../types.h"
constexpr bool test() {
std::ranges::transform_view<ContiguousView, Increment> transformView1;
auto iter1 = std::move(transformView1).begin();
std::ranges::transform_view<ContiguousView, Increment> transformView2;
auto iter2 = std::move(transformView2).begin();
iter1 += 4;
assert((iter1 + 1).base() == globalBuff + 5);
assert((1 + iter1).base() == globalBuff + 5);
assert((iter1 - 1).base() == globalBuff + 3);
assert(iter1 - iter2 == 4);
assert((iter1 + 2) - 2 == iter1);
assert((iter1 - 2) + 2 == iter1);
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// 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-no-concepts
// UNSUPPORTED: gcc-10
// The requirements for transform_view::<iterator>'s members.
#include <ranges>
#include "test_macros.h"
#include "../types.h"
static_assert(std::ranges::bidirectional_range<std::ranges::transform_view<BidirectionalView, IncrementConst>>);
static_assert(!std::ranges::bidirectional_range<std::ranges::transform_view<ForwardView, IncrementConst>>);
static_assert(std::ranges::random_access_range<std::ranges::transform_view<RandomAccessView, IncrementConst>>);
static_assert(!std::ranges::random_access_range<std::ranges::transform_view<BidirectionalView, IncrementConst>>);

View File

@ -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-no-concepts
// UNSUPPORTED: gcc-10
// class transform_view::<sentinel>;
#include <ranges>
#include "test_macros.h"
#include "../types.h"
template<class T>
concept EndIsIter = requires(T t) { ++t.end(); };
constexpr bool test() {
std::ranges::transform_view<SizedSentinelView, IncrementConst> transformView1;
// Going to const and back.
auto sent1 = transformView1.end();
std::ranges::sentinel_t<const std::ranges::transform_view<SizedSentinelView, IncrementConst>> sent2{sent1};
std::ranges::sentinel_t<const std::ranges::transform_view<SizedSentinelView, IncrementConst>> sent3{sent2};
(void)sent3;
static_assert(!EndIsIter<decltype(sent1)>);
static_assert(!EndIsIter<decltype(sent2)>);
assert(sent1.base() == globalBuff + 8);
std::ranges::transform_view transformView2(SizedSentinelView{4}, IncrementConst());
auto sent4 = transformView2.end();
auto iter = transformView1.begin();
{
assert(iter != sent1);
assert(iter != sent2);
assert(iter != sent4);
}
{
assert(iter + 8 == sent1);
assert(iter + 8 == sent2);
assert(iter + 4 == sent4);
}
{
assert(sent1 - iter == 8);
assert(sent4 - iter == 4);
assert(iter - sent1 == -8);
assert(iter - sent4 == -4);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
// transform_view::<iterator>::operator[]
#include <ranges>
#include "test_macros.h"
#include "../types.h"
constexpr bool test() {
int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7};
std::ranges::transform_view transformView1(ContiguousView{buff}, Increment{});
auto iter1 = std::move(transformView1).begin() + 1;
assert(iter1[0] == 2);
assert(iter1[4] == 6);
static_assert(!noexcept(
std::declval<std::ranges::iterator_t<std::ranges::transform_view<ContiguousView, Increment>>>()[0]));
static_assert( noexcept(
std::declval<std::ranges::iterator_t<std::ranges::transform_view<ContiguousView, IncrementNoexcept>>>()[0]));
ASSERT_SAME_TYPE(
int,
decltype(std::declval<std::ranges::transform_view<RandomAccessView, Increment>>().begin()[0]));
ASSERT_SAME_TYPE(
int&,
decltype(std::declval<std::ranges::transform_view<RandomAccessView, IncrementRef>>().begin()[0]));
ASSERT_SAME_TYPE(
int&&,
decltype(std::declval<std::ranges::transform_view<RandomAccessView, IncrementRvalueRef>>().begin()[0]));
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,93 @@
//===----------------------------------------------------------------------===//
//
// 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-no-concepts
// UNSUPPORTED: gcc-10
// transform_view::<iterator>::difference_type
// transform_view::<iterator>::value_type
// transform_view::<iterator>::iterator_category
// transform_view::<iterator>::iterator_concept
#include <ranges>
#include "test_macros.h"
#include "../types.h"
template<class V, class F>
concept HasIterCategory = requires { typename std::ranges::transform_view<V, F>::iterator_category; };
constexpr bool test() {
{
// Member typedefs for contiguous iterator.
static_assert(std::same_as<std::iterator_traits<int*>::iterator_concept, std::contiguous_iterator_tag>);
static_assert(std::same_as<std::iterator_traits<int*>::iterator_category, std::random_access_iterator_tag>);
using TView = std::ranges::transform_view<ContiguousView, IncrementRef>;
using TIter = std::ranges::iterator_t<TView>;
static_assert(std::same_as<typename TIter::iterator_concept, std::random_access_iterator_tag>);
static_assert(std::same_as<typename TIter::iterator_category, std::random_access_iterator_tag>);
static_assert(std::same_as<typename TIter::value_type, int>);
static_assert(std::same_as<typename TIter::difference_type, std::ptrdiff_t>);
}
{
// Member typedefs for random access iterator.
using TView = std::ranges::transform_view<RandomAccessView, IncrementRef>;
using TIter = std::ranges::iterator_t<TView>;
static_assert(std::same_as<typename TIter::iterator_concept, std::random_access_iterator_tag>);
static_assert(std::same_as<typename TIter::iterator_category, std::random_access_iterator_tag>);
static_assert(std::same_as<typename TIter::value_type, int>);
static_assert(std::same_as<typename TIter::difference_type, std::ptrdiff_t>);
}
{
// Member typedefs for random access iterator/not-lvalue-ref.
using TView = std::ranges::transform_view<RandomAccessView, Increment>;
using TIter = std::ranges::iterator_t<TView>;
static_assert(std::same_as<typename TIter::iterator_concept, std::random_access_iterator_tag>);
static_assert(std::same_as<typename TIter::iterator_category, std::input_iterator_tag>); // Note: this is now input_iterator_tag.
static_assert(std::same_as<typename TIter::value_type, int>);
static_assert(std::same_as<typename TIter::difference_type, std::ptrdiff_t>);
}
{
// Member typedefs for bidirectional iterator.
using TView = std::ranges::transform_view<BidirectionalView, IncrementRef>;
using TIter = std::ranges::iterator_t<TView>;
static_assert(std::same_as<typename TIter::iterator_concept, std::bidirectional_iterator_tag>);
static_assert(std::same_as<typename TIter::iterator_category, std::bidirectional_iterator_tag>);
static_assert(std::same_as<typename TIter::value_type, int>);
static_assert(std::same_as<typename TIter::difference_type, std::ptrdiff_t>);
}
{
// Member typedefs for forward iterator.
using TView = std::ranges::transform_view<ForwardView, IncrementRef>;
using TIter = std::ranges::iterator_t<TView>;
static_assert(std::same_as<typename TIter::iterator_concept, std::forward_iterator_tag>);
static_assert(std::same_as<typename TIter::iterator_category, std::forward_iterator_tag>);
static_assert(std::same_as<typename TIter::value_type, int>);
static_assert(std::same_as<typename TIter::difference_type, std::ptrdiff_t>);
}
{
// Member typedefs for input iterator.
using TView = std::ranges::transform_view<InputView, IncrementRef>;
using TIter = std::ranges::iterator_t<TView>;
static_assert(std::same_as<typename TIter::iterator_concept, std::input_iterator_tag>);
static_assert(!HasIterCategory<InputView, IncrementRef>);
static_assert(std::same_as<typename TIter::value_type, int>);
static_assert(std::same_as<typename TIter::difference_type, std::ptrdiff_t>);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,48 @@
//===----------------------------------------------------------------------===//
//
// 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-no-concepts
// UNSUPPORTED: gcc-10
// constexpr auto size() requires sized_range<V>
// constexpr auto size() const requires sized_range<const V>
#include <ranges>
#include "test_macros.h"
#include "types.h"
template<class T>
concept SizeInvocable = requires(T t) { t.size(); };
constexpr bool test() {
{
std::ranges::transform_view transformView(ContiguousView{}, Increment{});
assert(transformView.size() == 8);
}
{
const std::ranges::transform_view transformView(ContiguousView{globalBuff, 4}, Increment{});
assert(transformView.size() == 4);
}
static_assert(!SizeInvocable<std::ranges::transform_view<ForwardView, Increment>>);
static_assert(SizeInvocable<std::ranges::transform_view<SizedSentinelNotConstView, Increment>>);
static_assert(!SizeInvocable<const std::ranges::transform_view<SizedSentinelNotConstView, Increment>>);
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,155 @@
#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_TRANSFORM_TYPES_H
#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_TRANSFORM_TYPES_H
#include "test_macros.h"
#include "test_iterators.h"
#include "test_range.h"
int globalBuff[8] = {0,1,2,3,4,5,6,7};
template<class T, class F>
concept ValidDropView = requires { typename std::ranges::transform_view<T, F>; };
struct ContiguousView : std::ranges::view_base {
int start_;
int *ptr_;
constexpr ContiguousView(int* ptr = globalBuff, int start = 0) : start_(start), ptr_(ptr) {}
constexpr ContiguousView(ContiguousView&&) = default;
constexpr ContiguousView& operator=(ContiguousView&&) = default;
constexpr friend int* begin(ContiguousView& view) { return view.ptr_ + view.start_; }
constexpr friend int* begin(ContiguousView const& view) { return view.ptr_ + view.start_; }
constexpr friend int* end(ContiguousView& view) { return view.ptr_ + 8; }
constexpr friend int* end(ContiguousView const& view) { return view.ptr_ + 8; }
};
struct CopyableView : std::ranges::view_base {
int start_;
constexpr CopyableView(int start = 0) : start_(start) {}
constexpr CopyableView(CopyableView const&) = default;
constexpr CopyableView& operator=(CopyableView const&) = default;
constexpr friend int* begin(CopyableView& view) { return globalBuff + view.start_; }
constexpr friend int* begin(CopyableView const& view) { return globalBuff + view.start_; }
constexpr friend int* end(CopyableView&) { return globalBuff + 8; }
constexpr friend int* end(CopyableView const&) { return globalBuff + 8; }
};
using ForwardIter = forward_iterator<int*>;
struct ForwardView : std::ranges::view_base {
int *ptr_;
constexpr ForwardView(int* ptr = globalBuff) : ptr_(ptr) {}
constexpr ForwardView(ForwardView&&) = default;
constexpr ForwardView& operator=(ForwardView&&) = default;
constexpr friend ForwardIter begin(ForwardView& view) { return ForwardIter(view.ptr_); }
constexpr friend ForwardIter begin(ForwardView const& view) { return ForwardIter(view.ptr_); }
constexpr friend ForwardIter end(ForwardView& view) { return ForwardIter(view.ptr_ + 8); }
constexpr friend ForwardIter end(ForwardView const& view) { return ForwardIter(view.ptr_ + 8); }
};
using ForwardRange = test_common_range<forward_iterator>;
using RandomAccessIter = random_access_iterator<int*>;
struct RandomAccessView : std::ranges::view_base {
RandomAccessIter begin() const noexcept;
RandomAccessIter end() const noexcept;
RandomAccessIter begin() noexcept;
RandomAccessIter end() noexcept;
};
using BidirectionalIter = bidirectional_iterator<int*>;
struct BidirectionalView : std::ranges::view_base {
BidirectionalIter begin() const;
BidirectionalIter end() const;
BidirectionalIter begin();
BidirectionalIter end();
};
struct BorrowableRange {
friend int* begin(BorrowableRange const& range);
friend int* end(BorrowableRange const&);
friend int* begin(BorrowableRange& range);
friend int* end(BorrowableRange&);
};
template<>
inline constexpr bool std::ranges::enable_borrowed_range<BorrowableRange> = true;
struct InputView : std::ranges::view_base {
int *ptr_;
constexpr InputView(int* ptr = globalBuff) : ptr_(ptr) {}
constexpr cpp20_input_iterator<int*> begin() const { return cpp20_input_iterator<int*>(ptr_); }
constexpr int* end() const { return ptr_ + 8; }
constexpr cpp20_input_iterator<int*> begin() { return cpp20_input_iterator<int*>(ptr_); }
constexpr int* end() { return ptr_ + 8; }
};
constexpr bool operator==(const cpp20_input_iterator<int*> &lhs, int* rhs) { return lhs.base() == rhs; }
constexpr bool operator==(int* lhs, const cpp20_input_iterator<int*> &rhs) { return rhs.base() == lhs; }
struct SizedSentinelView : std::ranges::view_base {
int count_;
constexpr SizedSentinelView(int count = 8) : count_(count) {}
constexpr RandomAccessIter begin() const { return RandomAccessIter(globalBuff); }
constexpr int* end() const { return globalBuff + count_; }
constexpr RandomAccessIter begin() { return RandomAccessIter(globalBuff); }
constexpr int* end() { return globalBuff + count_; }
};
constexpr auto operator- (const RandomAccessIter &lhs, int* rhs) { return lhs.base() - rhs; }
constexpr auto operator- (int* lhs, const RandomAccessIter &rhs) { return lhs - rhs.base(); }
constexpr bool operator==(const RandomAccessIter &lhs, int* rhs) { return lhs.base() == rhs; }
constexpr bool operator==(int* lhs, const RandomAccessIter &rhs) { return rhs.base() == lhs; }
struct SizedSentinelNotConstView : std::ranges::view_base {
ForwardIter begin() const;
int *end() const;
ForwardIter begin();
int *end();
size_t size();
};
bool operator==(const ForwardIter &lhs, int* rhs);
bool operator==(int* lhs, const ForwardIter &rhs);
struct Range {
friend int* begin(Range const&);
friend int* end(Range const&);
friend int* begin(Range&);
friend int* end(Range&);
};
using CountedIter = stride_counting_iterator<forward_iterator<int*>>;
struct CountedView : std::ranges::view_base {
constexpr CountedIter begin() { return CountedIter(ForwardIter(globalBuff)); }
constexpr CountedIter begin() const { return CountedIter(ForwardIter(globalBuff)); }
constexpr CountedIter end() { return CountedIter(ForwardIter(globalBuff + 8)); }
constexpr CountedIter end() const { return CountedIter(ForwardIter(globalBuff + 8)); }
};
using ThreeWayCompIter = three_way_contiguous_iterator<int*>;
struct ThreeWayCompView : std::ranges::view_base {
constexpr ThreeWayCompIter begin() { return ThreeWayCompIter(globalBuff); }
constexpr ThreeWayCompIter begin() const { return ThreeWayCompIter(globalBuff); }
constexpr ThreeWayCompIter end() { return ThreeWayCompIter(globalBuff + 8); }
constexpr ThreeWayCompIter end() const { return ThreeWayCompIter(globalBuff + 8); }
};
struct Increment {
constexpr int operator()(int x) { return x + 1; }
};
struct IncrementConst {
constexpr int operator()(int x) const { return x + 1; }
};
struct IncrementRef {
constexpr int& operator()(int& x) { return ++x; }
};
struct IncrementRvalueRef {
constexpr int&& operator()(int& x) { return std::move(++x); }
};
struct IncrementNoexcept {
constexpr int operator()(int x) noexcept { return x + 1; }
};
#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_TRANSFORM_TYPES_H

View File

@ -875,6 +875,62 @@ private:
I base_ = I();
};
template <class It>
class three_way_contiguous_iterator
{
static_assert(std::is_pointer_v<It>, "Things probably break in this case");
It it_;
template <class U> friend class three_way_contiguous_iterator;
public:
typedef std::contiguous_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
typedef typename std::remove_pointer<It>::type element_type;
TEST_CONSTEXPR_CXX14 It base() const {return it_;}
TEST_CONSTEXPR_CXX14 three_way_contiguous_iterator() : it_() {}
explicit TEST_CONSTEXPR_CXX14 three_way_contiguous_iterator(It it) : it_(it) {}
template <class U>
TEST_CONSTEXPR_CXX14 three_way_contiguous_iterator(const three_way_contiguous_iterator<U>& u) : it_(u.it_) {}
TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;}
TEST_CONSTEXPR_CXX14 pointer operator->() const {return it_;}
TEST_CONSTEXPR_CXX14 three_way_contiguous_iterator& operator++() {++it_; return *this;}
TEST_CONSTEXPR_CXX14 three_way_contiguous_iterator operator++(int)
{three_way_contiguous_iterator tmp(*this); ++(*this); return tmp;}
TEST_CONSTEXPR_CXX14 three_way_contiguous_iterator& operator--() {--it_; return *this;}
TEST_CONSTEXPR_CXX14 three_way_contiguous_iterator operator--(int)
{three_way_contiguous_iterator tmp(*this); --(*this); return tmp;}
TEST_CONSTEXPR_CXX14 three_way_contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;}
TEST_CONSTEXPR_CXX14 three_way_contiguous_iterator operator+(difference_type n) const
{three_way_contiguous_iterator tmp(*this); tmp += n; return tmp;}
friend TEST_CONSTEXPR_CXX14 three_way_contiguous_iterator operator+(difference_type n, three_way_contiguous_iterator x)
{x += n; return x;}
TEST_CONSTEXPR_CXX14 three_way_contiguous_iterator& operator-=(difference_type n) {return *this += -n;}
TEST_CONSTEXPR_CXX14 three_way_contiguous_iterator operator-(difference_type n) const
{three_way_contiguous_iterator tmp(*this); tmp -= n; return tmp;}
TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return it_[n];}
template <class T>
void operator,(T const &) DELETE_FUNCTION;
friend TEST_CONSTEXPR_CXX14
difference_type operator-(const three_way_contiguous_iterator& x, const three_way_contiguous_iterator& y) {
return x.base() - y.base();
}
friend auto operator<=>(const three_way_contiguous_iterator&, const three_way_contiguous_iterator&) = default;
};
// clang-format on
#endif // TEST_STD_VER > 17 && defined(__cpp_lib_concepts)