[libc++] Implement adjacent_transform (#168208)
This patch implements std::ranges::adjacent_transform_view. This is part of P2321R2 tracked by #105169.
This commit is contained in:
parent
0952ccc712
commit
fc4661aa11
@ -38,8 +38,8 @@ What's New in Libc++ 22.0.0?
|
||||
Implemented Papers
|
||||
------------------
|
||||
|
||||
- P2321R2: ``zip`` (`Github <https://llvm.org/PR105169>`__) (The paper is partially implemented. ``zip_transform_view``
|
||||
and `adjacent_view` are implemented in this release)
|
||||
- P2321R2: ``zip`` (`Github <https://llvm.org/PR105169>`__) (The paper is partially implemented. ``zip_transform_view``,
|
||||
`adjacent_view`, and ``adjacent_transform_view`` are implemented in this release)
|
||||
- P2988R12: ``std::optional<T&>`` (`Github <https://llvm.org/PR148131>`__)
|
||||
- P3044R2: sub-``string_view`` from ``string`` (`Github <https://llvm.org/PR148140>`__)
|
||||
- P3223R2: Making ``std::istream::ignore`` less surprising (`Github <https://llvm.org/PR148178>`__)
|
||||
|
||||
@ -702,6 +702,7 @@ set(files
|
||||
__random/uniform_real_distribution.h
|
||||
__random/weibull_distribution.h
|
||||
__ranges/access.h
|
||||
__ranges/adjacent_transform_view.h
|
||||
__ranges/adjacent_view.h
|
||||
__ranges/all.h
|
||||
__ranges/as_rvalue_view.h
|
||||
|
||||
406
libcxx/include/__ranges/adjacent_transform_view.h
Normal file
406
libcxx/include/__ranges/adjacent_transform_view.h
Normal file
@ -0,0 +1,406 @@
|
||||
// -*- 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_ADJACENT_TRANSFORM_VIEW_H
|
||||
#define _LIBCPP___RANGES_ADJACENT_TRANSFORM_VIEW_H
|
||||
|
||||
#include <__config>
|
||||
|
||||
#include <__algorithm/min.h>
|
||||
#include <__compare/three_way_comparable.h>
|
||||
#include <__concepts/constructible.h>
|
||||
#include <__concepts/convertible_to.h>
|
||||
#include <__concepts/derived_from.h>
|
||||
#include <__concepts/equality_comparable.h>
|
||||
#include <__concepts/invocable.h>
|
||||
#include <__cstddef/size_t.h>
|
||||
#include <__functional/bind_back.h>
|
||||
#include <__functional/invoke.h>
|
||||
#include <__functional/operations.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/incrementable_traits.h>
|
||||
#include <__iterator/iter_move.h>
|
||||
#include <__iterator/iter_swap.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/next.h>
|
||||
#include <__iterator/prev.h>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/adjacent_view.h>
|
||||
#include <__ranges/all.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/empty_view.h>
|
||||
#include <__ranges/movable_box.h>
|
||||
#include <__ranges/range_adaptor.h>
|
||||
#include <__ranges/size.h>
|
||||
#include <__ranges/view_interface.h>
|
||||
#include <__ranges/zip_transform_view.h>
|
||||
#include <__type_traits/common_type.h>
|
||||
#include <__type_traits/decay.h>
|
||||
#include <__type_traits/is_nothrow_constructible.h>
|
||||
#include <__type_traits/is_object.h>
|
||||
#include <__type_traits/is_referenceable.h>
|
||||
#include <__type_traits/make_unsigned.h>
|
||||
#include <__type_traits/maybe_const.h>
|
||||
#include <__utility/declval.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <__utility/in_place.h>
|
||||
#include <__utility/integer_sequence.h>
|
||||
#include <__utility/move.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_PUSH_MACROS
|
||||
#include <__undef_macros>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER >= 23
|
||||
|
||||
namespace ranges {
|
||||
|
||||
template <class _Fn, size_t _Np>
|
||||
struct __apply_n {
|
||||
template <class _Tp, size_t... _Is>
|
||||
static auto __apply(index_sequence<_Is...>) -> invoke_result_t<_Fn, decltype((void)_Is, std::declval<_Tp>())...>;
|
||||
|
||||
template <class _Tp>
|
||||
static auto operator()(_Tp&&) -> decltype(__apply<_Tp>(make_index_sequence<_Np>{}));
|
||||
};
|
||||
|
||||
template <forward_range _View, move_constructible _Fn, size_t _Np>
|
||||
requires view<_View> && (_Np > 0) && is_object_v<_Fn> &&
|
||||
regular_invocable<__apply_n<_Fn&, _Np>, range_reference_t<_View>> &&
|
||||
__referenceable<invoke_result_t<__apply_n<_Fn&, _Np>, range_reference_t<_View>>>
|
||||
class adjacent_transform_view : public view_interface<adjacent_transform_view<_View, _Fn, _Np>> {
|
||||
private:
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS adjacent_view<_View, _Np> __inner_;
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS __movable_box<_Fn> __fun_;
|
||||
|
||||
using _InnerView _LIBCPP_NODEBUG = adjacent_view<_View, _Np>;
|
||||
|
||||
template <bool _Const>
|
||||
using __inner_iterator _LIBCPP_NODEBUG = iterator_t<__maybe_const<_Const, _InnerView>>;
|
||||
|
||||
template <bool _Const>
|
||||
using __inner_sentinel _LIBCPP_NODEBUG = sentinel_t<__maybe_const<_Const, _InnerView>>;
|
||||
|
||||
template <bool>
|
||||
class __iterator;
|
||||
|
||||
template <bool>
|
||||
class __sentinel;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI adjacent_transform_view() = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit adjacent_transform_view(_View __base, _Fn __fun)
|
||||
: __inner_(std::move(__base)), __fun_(std::in_place, std::move(__fun)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
|
||||
requires copy_constructible<_View>
|
||||
{
|
||||
return __inner_.base();
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__inner_).base(); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto begin() { return __iterator<false>(*this, __inner_.begin()); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
|
||||
requires range<const _InnerView> && regular_invocable<__apply_n<const _Fn&, _Np>, range_reference_t<const _View>>
|
||||
{
|
||||
return __iterator<true>(*this, __inner_.begin());
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto end() {
|
||||
if constexpr (common_range<_InnerView>) {
|
||||
return __iterator<false>(*this, __inner_.end());
|
||||
} else {
|
||||
return __sentinel<false>(__inner_.end());
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto end() const
|
||||
requires range<const _InnerView> && regular_invocable<__apply_n<const _Fn&, _Np>, range_reference_t<const _View>>
|
||||
{
|
||||
if constexpr (common_range<const _InnerView>) {
|
||||
return __iterator<true>(*this, __inner_.end());
|
||||
} else {
|
||||
return __sentinel<true>(__inner_.end());
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto size()
|
||||
requires sized_range<_InnerView>
|
||||
{
|
||||
return __inner_.size();
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto size() const
|
||||
requires sized_range<const _InnerView>
|
||||
{
|
||||
return __inner_.size();
|
||||
}
|
||||
};
|
||||
|
||||
template <forward_range _View, move_constructible _Fn, size_t _Np>
|
||||
requires view<_View> && (_Np > 0) && is_object_v<_Fn> &&
|
||||
regular_invocable<__apply_n<_Fn&, _Np>, range_reference_t<_View>> &&
|
||||
__referenceable<invoke_result_t<__apply_n<_Fn&, _Np>, range_reference_t<_View>>>
|
||||
template <bool _Const>
|
||||
class adjacent_transform_view<_View, _Fn, _Np>::__iterator {
|
||||
friend adjacent_transform_view;
|
||||
|
||||
using _Parent _LIBCPP_NODEBUG = __maybe_const<_Const, adjacent_transform_view>;
|
||||
using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>;
|
||||
|
||||
_Parent* __parent_ = nullptr;
|
||||
__inner_iterator<_Const> __inner_;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent, __inner_iterator<_Const> __inner)
|
||||
: __parent_(std::addressof(__parent)), __inner_(std::move(__inner)) {}
|
||||
|
||||
static consteval auto __get_iterator_category() {
|
||||
using _Cat = iterator_traits<iterator_t<_Base>>::iterator_category;
|
||||
if constexpr (!is_reference_v<
|
||||
invoke_result_t<__apply_n<__maybe_const<_Const, _Fn>&, _Np>, range_reference_t<_Base>>>)
|
||||
return input_iterator_tag{};
|
||||
else if constexpr (derived_from<_Cat, random_access_iterator_tag>)
|
||||
return random_access_iterator_tag{};
|
||||
else if constexpr (derived_from<_Cat, bidirectional_iterator_tag>)
|
||||
return bidirectional_iterator_tag{};
|
||||
else if constexpr (derived_from<_Cat, forward_iterator_tag>)
|
||||
return forward_iterator_tag{};
|
||||
else
|
||||
return input_iterator_tag{};
|
||||
}
|
||||
|
||||
template <size_t... _Is>
|
||||
static consteval bool __noexcept_dereference(index_sequence<_Is...>) {
|
||||
return noexcept(std::invoke(
|
||||
std::declval<__maybe_const<_Const, _Fn>&>(), ((void)_Is, *std::declval<iterator_t<_Base> const&>())...));
|
||||
}
|
||||
|
||||
public:
|
||||
using iterator_category = decltype(__get_iterator_category());
|
||||
using iterator_concept = typename __inner_iterator<_Const>::iterator_concept;
|
||||
using value_type =
|
||||
remove_cvref_t<invoke_result_t<__apply_n<__maybe_const<_Const, _Fn>&, _Np>, range_reference_t<_Base>>>;
|
||||
using difference_type = range_difference_t<_Base>;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __iterator() = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
|
||||
requires _Const && convertible_to<__inner_iterator<false>, __inner_iterator<true>>
|
||||
: __parent_(__i.__parent_), __inner_(std::move(__i.__inner_)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const
|
||||
noexcept(__noexcept_dereference(make_index_sequence<_Np>{})) {
|
||||
return std::apply(
|
||||
[&](const auto&... __iters) -> decltype(auto) { return std::invoke(*__parent_->__fun_, *__iters...); },
|
||||
__adjacent_view_iter_access::__get_current(__inner_));
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
|
||||
++__inner_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) {
|
||||
auto __tmp = *this;
|
||||
++*this;
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
|
||||
requires bidirectional_range<_Base>
|
||||
{
|
||||
--__inner_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
|
||||
requires bidirectional_range<_Base>
|
||||
{
|
||||
auto __tmp = *this;
|
||||
--*this;
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __x)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
__inner_ += __x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __x)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
__inner_ -= __x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return std::apply(
|
||||
[&](const auto&... __iters) -> decltype(auto) { return std::invoke(*__parent_->__fun_, __iters[__n]...); },
|
||||
__adjacent_view_iter_access::__get_current(__inner_));
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) {
|
||||
return __x.__inner_ == __y.__inner_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const __iterator& __x, const __iterator& __y)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return __x.__inner_ < __y.__inner_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const __iterator& __x, const __iterator& __y)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return __x.__inner_ > __y.__inner_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return __x.__inner_ <= __y.__inner_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return __x.__inner_ >= __y.__inner_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y)
|
||||
requires random_access_range<_Base> && three_way_comparable<__inner_iterator<_Const>>
|
||||
{
|
||||
return __x.__inner_ <=> __y.__inner_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, difference_type __n)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return __iterator(*__i.__parent_, __i.__inner_ + __n);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __i)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return __iterator(*__i.__parent_, __i.__inner_ + __n);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, difference_type __n)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return __iterator(*__i.__parent_, __i.__inner_ - __n);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y)
|
||||
requires sized_sentinel_for<__inner_iterator<_Const>, __inner_iterator<_Const>>
|
||||
{
|
||||
return __x.__inner_ - __y.__inner_;
|
||||
}
|
||||
};
|
||||
|
||||
template <forward_range _View, move_constructible _Fn, size_t _Np>
|
||||
requires view<_View> && (_Np > 0) && is_object_v<_Fn> &&
|
||||
regular_invocable<__apply_n<_Fn&, _Np>, range_reference_t<_View>> &&
|
||||
__referenceable<invoke_result_t<__apply_n<_Fn&, _Np>, range_reference_t<_View>>>
|
||||
template <bool _Const>
|
||||
class adjacent_transform_view<_View, _Fn, _Np>::__sentinel {
|
||||
friend adjacent_transform_view;
|
||||
|
||||
__inner_sentinel<_Const> __inner_;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(__inner_sentinel<_Const> __inner)
|
||||
: __inner_(std::move(__inner)) {}
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __i)
|
||||
requires _Const && convertible_to<__inner_sentinel<false>, __inner_sentinel<_Const>>
|
||||
: __inner_(std::move(__i.__inner_)) {}
|
||||
|
||||
template <bool _OtherConst>
|
||||
requires sentinel_for<__inner_sentinel<_Const>, __inner_iterator<_OtherConst>>
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
|
||||
return __x.__inner_ == __y.__inner_;
|
||||
}
|
||||
|
||||
template <bool _OtherConst>
|
||||
requires sized_sentinel_for<__inner_sentinel<_Const>, __inner_iterator<_OtherConst>>
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _InnerView>>
|
||||
operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
|
||||
return __x.__inner_ - __y.__inner_;
|
||||
}
|
||||
|
||||
template <bool _OtherConst>
|
||||
requires sized_sentinel_for<__inner_sentinel<_Const>, __inner_iterator<_OtherConst>>
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _InnerView>>
|
||||
operator-(const __sentinel& __x, const __iterator<_OtherConst>& __y) {
|
||||
return __x.__inner_ - __y.__inner_;
|
||||
}
|
||||
};
|
||||
|
||||
namespace views {
|
||||
namespace __adjacent_transform {
|
||||
|
||||
template <size_t _Np>
|
||||
struct __fn : __range_adaptor_closure<__fn<_Np>> {
|
||||
template <class _Range, class _Fn>
|
||||
requires(_Np == 0 && forward_range<_Range &&>)
|
||||
_LIBCPP_HIDE_FROM_ABI static constexpr auto
|
||||
operator()(_Range&&, _Fn&& __fn) noexcept(noexcept(views::zip_transform(std::forward<_Fn>(__fn))))
|
||||
-> decltype(views::zip_transform(std::forward<_Fn>(__fn))) {
|
||||
return views::zip_transform(std::forward<_Fn>(__fn));
|
||||
}
|
||||
|
||||
template <class _Range, class _Fn>
|
||||
_LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&& __range, _Fn&& __fn) noexcept(
|
||||
noexcept(adjacent_transform_view<views::all_t<_Range&&>, decay_t<_Fn>, _Np>(
|
||||
std::forward<_Range>(__range), std::forward<_Fn>(__fn))))
|
||||
-> decltype(adjacent_transform_view<views::all_t<_Range&&>, decay_t<_Fn>, _Np>(
|
||||
std::forward<_Range>(__range), std::forward<_Fn>(__fn))) {
|
||||
return adjacent_transform_view<views::all_t<_Range&&>, decay_t<_Fn>, _Np>(
|
||||
std::forward<_Range>(__range), std::forward<_Fn>(__fn));
|
||||
}
|
||||
|
||||
template <class _Fn>
|
||||
requires constructible_from<decay_t<_Fn>, _Fn>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Fn&& __f) const
|
||||
noexcept(is_nothrow_constructible_v<decay_t<_Fn>, _Fn>) {
|
||||
return __pipeable(std::__bind_back(*this, std::forward<_Fn>(__f)));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace __adjacent_transform
|
||||
inline namespace __cpo {
|
||||
template <size_t _Np>
|
||||
inline constexpr auto adjacent_transform = __adjacent_transform::__fn<_Np>{};
|
||||
inline constexpr auto pairwise_transform = adjacent_transform<2>;
|
||||
} // namespace __cpo
|
||||
} // namespace views
|
||||
} // namespace ranges
|
||||
|
||||
#endif // _LIBCPP_STD_VER >= 23
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // _LIBCPP___RANGES_ADJACENT_TRANSFORM_VIEW_H
|
||||
@ -141,10 +141,18 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct __adjacent_view_iter_access {
|
||||
template <class _Iter>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr static auto& __get_current(_Iter& __it) noexcept {
|
||||
return __it.__current_;
|
||||
}
|
||||
};
|
||||
|
||||
template <forward_range _View, size_t _Np>
|
||||
requires view<_View> && (_Np > 0)
|
||||
template <bool _Const>
|
||||
class adjacent_view<_View, _Np>::__iterator {
|
||||
friend __adjacent_view_iter_access;
|
||||
friend adjacent_view;
|
||||
using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>;
|
||||
array<iterator_t<_Base>, _Np> __current_ = array<iterator_t<_Base>, _Np>();
|
||||
|
||||
@ -1852,6 +1852,7 @@ module std [system] {
|
||||
|
||||
module ranges {
|
||||
module access { header "__ranges/access.h" }
|
||||
module adjacent_transform_view { header "__ranges/adjacent_transform_view.h" }
|
||||
module adjacent_view { header "__ranges/adjacent_view.h" }
|
||||
module all {
|
||||
header "__ranges/all.h"
|
||||
|
||||
@ -372,6 +372,17 @@ namespace std::ranges {
|
||||
inline constexpr auto pairwise = adjacent<2>;
|
||||
}
|
||||
|
||||
// [range.adjacent.transform], adjacent transform view
|
||||
template<forward_range V, move_constructible F, size_t N>
|
||||
requires see below
|
||||
class adjacent_transform_view;
|
||||
|
||||
namespace views {
|
||||
template<size_t N>
|
||||
constexpr unspecified adjacent_transform = unspecified;
|
||||
inline constexpr auto pairwise_transform = adjacent_transform<2>;
|
||||
}
|
||||
|
||||
// [range.as.rvalue]
|
||||
template <view V>
|
||||
requires input_range<V>
|
||||
@ -467,6 +478,7 @@ namespace std {
|
||||
# endif
|
||||
|
||||
# if _LIBCPP_STD_VER >= 23
|
||||
# include <__ranges/adjacent_transform_view.h>
|
||||
# include <__ranges/adjacent_view.h>
|
||||
# include <__ranges/as_rvalue_view.h>
|
||||
# include <__ranges/chunk_by_view.h>
|
||||
|
||||
@ -308,9 +308,6 @@ export namespace std {
|
||||
using std::ranges::views::pairwise;
|
||||
} // namespace views
|
||||
|
||||
#endif // _LIBCPP_STD_VER >= 23
|
||||
|
||||
#if 0
|
||||
using std::ranges::adjacent_transform_view;
|
||||
|
||||
namespace views {
|
||||
@ -318,6 +315,9 @@ export namespace std {
|
||||
using std::ranges::views::pairwise_transform;
|
||||
} // namespace views
|
||||
|
||||
#endif // _LIBCPP_STD_VER >= 23
|
||||
|
||||
#if 0
|
||||
using std::ranges::chunk_view;
|
||||
|
||||
using std::ranges::chunk_view<V>;
|
||||
|
||||
@ -0,0 +1,275 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// Test std::views::adjacent_transform<N>
|
||||
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
|
||||
#include "helpers.h"
|
||||
#include "../range_adaptor_types.h"
|
||||
|
||||
struct Fn {
|
||||
int operator()(auto...) const;
|
||||
};
|
||||
|
||||
struct VoidFn {
|
||||
void operator()(auto...) const;
|
||||
};
|
||||
|
||||
struct StringFn {
|
||||
template <class... Ts>
|
||||
requires(sizeof...(Ts) > 0 && (std::is_same_v<Ts, std::string> && ...))
|
||||
int operator()(Ts...) const;
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test_constraints() {
|
||||
// needs to be a range
|
||||
static_assert(std::is_invocable_v<decltype((std::views::adjacent_transform<N>)), std::ranges::empty_view<int>, Fn>);
|
||||
static_assert(!std::is_invocable_v<decltype((std::views::adjacent_transform<N>)), int, Fn>);
|
||||
|
||||
// underlying needs to be forward_range
|
||||
static_assert(std::is_invocable_v<decltype((std::views::adjacent_transform<N>)), ForwardSizedView, Fn>);
|
||||
static_assert(!std::is_invocable_v<decltype((std::views::adjacent_transform<N>)), InputCommonView, Fn>);
|
||||
|
||||
// function needs to be callable with N range references
|
||||
static_assert(std::is_invocable_v<decltype((std::views::adjacent_transform<N>)), ForwardSizedView, Fn>);
|
||||
static_assert(!std::is_invocable_v<decltype((std::views::adjacent_transform<N>)), ForwardSizedView, StringFn>);
|
||||
|
||||
// results need to be referenceable
|
||||
static_assert(std::is_invocable_v<decltype((std::views::adjacent_transform<N>)), ForwardSizedView, Fn>);
|
||||
static_assert(!std::is_invocable_v<decltype((std::views::adjacent_transform<N>)), ForwardSizedView, VoidFn>);
|
||||
}
|
||||
|
||||
constexpr void test_pairwise_transform_constraints() {
|
||||
// needs to be a range
|
||||
static_assert(std::is_invocable_v<decltype((std::views::pairwise_transform)), std::ranges::empty_view<int>, Fn>);
|
||||
static_assert(!std::is_invocable_v<decltype((std::views::pairwise_transform)), int, Fn>);
|
||||
|
||||
// underlying needs to be forward_range
|
||||
static_assert(!std::is_invocable_v<decltype((std::views::pairwise_transform)), InputCommonView, Fn>);
|
||||
static_assert(std::is_invocable_v<decltype((std::views::pairwise_transform)), ForwardSizedView, Fn>);
|
||||
|
||||
// function needs to be callable with N range references
|
||||
static_assert(std::is_invocable_v<decltype((std::views::pairwise_transform)), ForwardSizedView, Fn>);
|
||||
static_assert(!std::is_invocable_v<decltype((std::views::pairwise_transform)), ForwardSizedView, StringFn>);
|
||||
|
||||
// results need to be referenceable
|
||||
static_assert(std::is_invocable_v<decltype((std::views::pairwise_transform)), ForwardSizedView, Fn>);
|
||||
static_assert(!std::is_invocable_v<decltype((std::views::pairwise_transform)), ForwardSizedView, VoidFn>);
|
||||
}
|
||||
|
||||
constexpr void test_all_constraints() {
|
||||
test_pairwise_transform_constraints();
|
||||
test_constraints<0>();
|
||||
test_constraints<1>();
|
||||
test_constraints<2>();
|
||||
test_constraints<3>();
|
||||
test_constraints<5>();
|
||||
}
|
||||
|
||||
constexpr void test_zero_case() {
|
||||
// N == 0 is a special case that always results in an empty range
|
||||
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
std::same_as<std::ranges::empty_view<int>> decltype(auto) v =
|
||||
std::views::adjacent_transform<0>(ContiguousCommonView{buffer}, Fn{});
|
||||
assert(std::ranges::size(v) == 0);
|
||||
}
|
||||
|
||||
struct MoveOnlyView : ForwardSizedView {
|
||||
using ForwardSizedView::ForwardSizedView;
|
||||
|
||||
constexpr MoveOnlyView(MoveOnlyView&&) = default;
|
||||
constexpr MoveOnlyView(const MoveOnlyView&) = delete;
|
||||
|
||||
constexpr MoveOnlyView& operator=(MoveOnlyView&&) = default;
|
||||
constexpr MoveOnlyView& operator=(const MoveOnlyView&) = delete;
|
||||
};
|
||||
|
||||
template <std::size_t N, class Fn, class Validator>
|
||||
constexpr void test() {
|
||||
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
Validator validator{};
|
||||
|
||||
// Test `views::adjacent_transform<N>(r)`
|
||||
{
|
||||
using View = std::ranges::adjacent_transform_view<ContiguousCommonView, Fn, N>;
|
||||
std::same_as<View> decltype(auto) v = std::views::adjacent_transform<N>(ContiguousCommonView{buffer}, Fn{});
|
||||
assert(std::ranges::size(v) == (N <= 8 ? 9 - N : 0));
|
||||
auto it = v.begin();
|
||||
validator(buffer, *it, 0);
|
||||
}
|
||||
|
||||
// Test `views::adjacent_transform<N>(move only view)`
|
||||
{
|
||||
using View = std::ranges::adjacent_transform_view<MoveOnlyView, Fn, N>;
|
||||
std::same_as<View> decltype(auto) v = std::views::adjacent_transform<N>(MoveOnlyView{buffer}, Fn{});
|
||||
assert(std::ranges::size(v) == (N <= 8 ? 9 - N : 0));
|
||||
auto it = v.begin();
|
||||
validator(buffer, *it, 0);
|
||||
}
|
||||
|
||||
// Test `r | views::adjacent_transform<N>`
|
||||
{
|
||||
using View = std::ranges::adjacent_transform_view<ContiguousCommonView, Fn, N>;
|
||||
std::same_as<View> decltype(auto) v = ContiguousCommonView{buffer} | std::views::adjacent_transform<N>(Fn{});
|
||||
assert(std::ranges::size(v) == (N <= 8 ? 9 - N : 0));
|
||||
auto it = v.begin();
|
||||
validator(buffer, *it, 0);
|
||||
}
|
||||
|
||||
// Test `move only view | views::adjacent_transform<N>`
|
||||
{
|
||||
using View = std::ranges::adjacent_transform_view<MoveOnlyView, Fn, N>;
|
||||
std::same_as<View> decltype(auto) v = MoveOnlyView{buffer} | std::views::adjacent_transform<N>(Fn{});
|
||||
assert(std::ranges::size(v) == (N <= 8 ? 9 - N : 0));
|
||||
auto it = v.begin();
|
||||
validator(buffer, *it, 0);
|
||||
}
|
||||
|
||||
// Test adjacent_transform<N> | adjacent_transform<N>
|
||||
{
|
||||
using View = std::ranges::
|
||||
adjacent_transform_view<std::ranges::adjacent_transform_view<ContiguousCommonView, MakeTuple, N>, MakeTuple, N>;
|
||||
|
||||
auto twice = std::views::adjacent_transform<N>(MakeTuple{}) | std::views::adjacent_transform<N>(MakeTuple{});
|
||||
std::same_as<View> decltype(auto) v = ContiguousCommonView{buffer} | twice;
|
||||
assert(std::ranges::size(v) == (N <= 5 ? 10 - 2 * N : 0));
|
||||
|
||||
if (std::ranges::size(v) == 0)
|
||||
return;
|
||||
|
||||
auto it = v.begin();
|
||||
auto nestedTuple = *it;
|
||||
|
||||
auto innerFirstTuple = std::get<0>(nestedTuple);
|
||||
|
||||
assert(std::get<0>(innerFirstTuple) == buffer[0]);
|
||||
if constexpr (N >= 2)
|
||||
assert(std::get<1>(innerFirstTuple) == buffer[1]);
|
||||
if constexpr (N >= 3)
|
||||
assert(std::get<2>(innerFirstTuple) == buffer[2]);
|
||||
if constexpr (N >= 4)
|
||||
assert(std::get<3>(innerFirstTuple) == buffer[3]);
|
||||
if constexpr (N >= 5)
|
||||
assert(std::get<4>(innerFirstTuple) == buffer[4]);
|
||||
|
||||
if constexpr (N >= 2) {
|
||||
auto innerSecondTuple = std::get<1>(nestedTuple);
|
||||
assert(std::get<0>(innerSecondTuple) == buffer[1]);
|
||||
if constexpr (N >= 3)
|
||||
assert(std::get<1>(innerSecondTuple) == buffer[2]);
|
||||
if constexpr (N >= 4)
|
||||
assert(std::get<2>(innerSecondTuple) == buffer[3]);
|
||||
if constexpr (N >= 5)
|
||||
assert(std::get<3>(innerSecondTuple) == buffer[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void test_pairwise_transform() {
|
||||
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
{
|
||||
// Test `views::pairwise_transform(r)`
|
||||
using View = std::ranges::adjacent_transform_view<ContiguousCommonView, MakeTuple, 2>;
|
||||
std::same_as<View> decltype(auto) v = std::views::pairwise_transform(ContiguousCommonView{buffer}, MakeTuple{});
|
||||
assert(std::ranges::size(v) == 7);
|
||||
auto it = v.begin();
|
||||
auto tuple = *it;
|
||||
assert(std::get<0>(tuple) == buffer[0]);
|
||||
assert(std::get<1>(tuple) == buffer[1]);
|
||||
}
|
||||
|
||||
{
|
||||
// Test `views::pairwise_transform(move only view)`
|
||||
using View = std::ranges::adjacent_transform_view<MoveOnlyView, MakeTuple, 2>;
|
||||
std::same_as<View> decltype(auto) v = std::views::pairwise_transform(MoveOnlyView{buffer}, MakeTuple{});
|
||||
assert(std::ranges::size(v) == 7);
|
||||
auto it = v.begin();
|
||||
auto tuple = *it;
|
||||
assert(std::get<0>(tuple) == buffer[0]);
|
||||
assert(std::get<1>(tuple) == buffer[1]);
|
||||
}
|
||||
{
|
||||
// Test `r | views::pairwise_transform`
|
||||
using View = std::ranges::adjacent_transform_view<ContiguousCommonView, MakeTuple, 2>;
|
||||
std::same_as<View> decltype(auto) v = ContiguousCommonView{buffer} | std::views::pairwise_transform(MakeTuple{});
|
||||
assert(std::ranges::size(v) == 7);
|
||||
auto it = v.begin();
|
||||
auto tuple = *it;
|
||||
assert(std::get<0>(tuple) == buffer[0]);
|
||||
assert(std::get<1>(tuple) == buffer[1]);
|
||||
}
|
||||
{
|
||||
// Test `move only view | views::pairwise_transform`
|
||||
using View = std::ranges::adjacent_transform_view<MoveOnlyView, MakeTuple, 2>;
|
||||
std::same_as<View> decltype(auto) v = MoveOnlyView{buffer} | std::views::pairwise_transform(MakeTuple{});
|
||||
assert(std::ranges::size(v) == 7);
|
||||
auto it = v.begin();
|
||||
auto tuple = *it;
|
||||
assert(std::get<0>(tuple) == buffer[0]);
|
||||
assert(std::get<1>(tuple) == buffer[1]);
|
||||
}
|
||||
{
|
||||
// Test pairwise_transform | pairwise_transform
|
||||
using View = std::ranges::
|
||||
adjacent_transform_view<std::ranges::adjacent_transform_view<ContiguousCommonView, MakeTuple, 2>, MakeTuple, 2>;
|
||||
|
||||
auto twice = std::views::pairwise_transform(MakeTuple{}) | std::views::pairwise_transform(MakeTuple{});
|
||||
std::same_as<View> decltype(auto) v = ContiguousCommonView{buffer} | twice;
|
||||
assert(std::ranges::size(v) == 6);
|
||||
|
||||
auto it = v.begin();
|
||||
auto nestedTuple = *it;
|
||||
|
||||
auto innerFirstTuple = std::get<0>(nestedTuple);
|
||||
|
||||
assert(std::get<0>(innerFirstTuple) == buffer[0]);
|
||||
assert(std::get<1>(innerFirstTuple) == buffer[1]);
|
||||
|
||||
auto innerSecondTuple = std::get<1>(nestedTuple);
|
||||
assert(std::get<0>(innerSecondTuple) == buffer[1]);
|
||||
assert(std::get<1>(innerSecondTuple) == buffer[2]);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple, ValidateTupleFromIndex<N>>();
|
||||
test<N, Tie, ValidateTieFromIndex<N>>();
|
||||
test<N, GetFirst, ValidateGetFirstFromIndex<N>>();
|
||||
test<N, Multiply, ValidateMultiplyFromIndex<N>>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_all_constraints();
|
||||
test_zero_case();
|
||||
test_pairwise_transform();
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<5>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// constexpr View base() const& requires copy_constructible<View>;
|
||||
// constexpr View base() &&;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
template <std::size_t N>
|
||||
constexpr explicit Range(int (&buffer)[N]) : begin_(&buffer[0]), end_(&buffer[0] + N) {}
|
||||
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;
|
||||
};
|
||||
|
||||
static_assert(std::ranges::view<Range>);
|
||||
static_assert(std::ranges::forward_range<Range>);
|
||||
|
||||
struct NonCopyableRange : std::ranges::view_base {
|
||||
explicit NonCopyableRange(int*, int*);
|
||||
NonCopyableRange(NonCopyableRange const&) = delete;
|
||||
NonCopyableRange(NonCopyableRange&&) = default;
|
||||
NonCopyableRange& operator=(NonCopyableRange const&) = default;
|
||||
NonCopyableRange& operator=(NonCopyableRange&&) = default;
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
static_assert(!std::copy_constructible<NonCopyableRange>);
|
||||
|
||||
template <typename T>
|
||||
concept CanCallBaseOn = requires(T t) { std::forward<T>(t).base(); };
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test() {
|
||||
int buff[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
// Check the const& overload
|
||||
{
|
||||
Range range(buff);
|
||||
auto view = range | std::views::adjacent_transform<N>(Fn{});
|
||||
|
||||
std::same_as<Range> decltype(auto) result = view.base();
|
||||
assert(result.wasCopyInitialized);
|
||||
assert(result.begin() == buff);
|
||||
assert(result.end() == buff + 9);
|
||||
}
|
||||
|
||||
// Check the && overload
|
||||
{
|
||||
Range range(buff);
|
||||
auto view = range | std::views::adjacent_transform<N>(Fn{});
|
||||
std::same_as<Range> decltype(auto) result = std::move(view).base();
|
||||
assert(result.wasMoveInitialized);
|
||||
assert(result.begin() == buff);
|
||||
assert(result.end() == buff + 9);
|
||||
}
|
||||
|
||||
// Ensure the const& overload is not considered when the base is not copy-constructible
|
||||
{
|
||||
static_assert(!CanCallBaseOn<std::ranges::adjacent_transform_view<NonCopyableRange, Fn, N> const&>);
|
||||
static_assert(!CanCallBaseOn<std::ranges::adjacent_transform_view<NonCopyableRange, Fn, N>&>);
|
||||
static_assert(!CanCallBaseOn<std::ranges::adjacent_transform_view<NonCopyableRange, Fn, N> const&&>);
|
||||
static_assert(CanCallBaseOn<std::ranges::adjacent_transform_view<NonCopyableRange, Fn, N>&&>);
|
||||
static_assert(CanCallBaseOn<std::ranges::adjacent_transform_view<NonCopyableRange, Fn, N>>);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple>();
|
||||
test<N, Tie>();
|
||||
test<N, GetFirst>();
|
||||
test<N, Multiply>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// constexpr auto begin();
|
||||
// constexpr auto begin() const requires range<const InnerView> &&
|
||||
// regular_invocable<const F&, REPEAT(range_reference_t<const V>, N)...>
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "helpers.h"
|
||||
#include "../range_adaptor_types.h"
|
||||
|
||||
template <class T>
|
||||
concept HasConstBegin = requires(const T& ct) { ct.begin(); };
|
||||
|
||||
template <class T>
|
||||
concept HasBegin = requires(T& t) { t.begin(); };
|
||||
|
||||
struct NoConstBeginView : std::ranges::view_base {
|
||||
int* begin();
|
||||
int* end();
|
||||
};
|
||||
|
||||
struct OnlyNonConstFn {
|
||||
template <class... T>
|
||||
requires((!std::is_const_v<std::remove_reference_t<T>>) && ...)
|
||||
int operator()(T&&...) const;
|
||||
};
|
||||
|
||||
template <class Range, class Fn, std::size_t N, class Validator>
|
||||
constexpr void test_one() {
|
||||
using View = std::ranges::adjacent_transform_view<Range, Fn, N>;
|
||||
Validator validator{};
|
||||
{
|
||||
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
View v(Range{buffer}, Fn{});
|
||||
|
||||
auto it = v.begin();
|
||||
validator(buffer, *it, 0);
|
||||
|
||||
auto cit = std::as_const(v).begin();
|
||||
validator(buffer, *cit, 0);
|
||||
}
|
||||
|
||||
{
|
||||
// empty range
|
||||
std::array<int, 0> buffer = {};
|
||||
View v(Range{buffer.data(), 0}, Fn{});
|
||||
auto it = v.begin();
|
||||
auto cit = std::as_const(v).begin();
|
||||
assert(it == v.end());
|
||||
assert(cit == std::as_const(v).end());
|
||||
}
|
||||
|
||||
if constexpr (N > 2) {
|
||||
// N greater than range size
|
||||
int buffer[2] = {1, 2};
|
||||
View v(Range{buffer}, Fn{});
|
||||
auto it = v.begin();
|
||||
auto cit = std::as_const(v).begin();
|
||||
assert(it == v.end());
|
||||
assert(cit == std::as_const(v).end());
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn, class Validator>
|
||||
constexpr void test_simple() {
|
||||
test_one<SimpleCommon, Fn, N, Validator>();
|
||||
|
||||
using View = std::ranges::adjacent_transform_view<SimpleCommon, MakeTuple, N>;
|
||||
|
||||
// non-const begin always exists and return iterator<false>
|
||||
static_assert(!std::is_same_v<std::ranges::iterator_t<View>, std::ranges::iterator_t<const View>>);
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn, class Validator>
|
||||
constexpr void test_non_simple() {
|
||||
test_one<NonSimpleCommon, Fn, N, Validator>();
|
||||
|
||||
using View = std::ranges::adjacent_transform_view<NonSimpleCommon, MakeTuple, N>;
|
||||
static_assert(!std::is_same_v<std::ranges::iterator_t<View>, std::ranges::iterator_t<const View>>);
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test_simple<N, MakeTuple, ValidateTupleFromIndex<N>>();
|
||||
test_simple<N, Tie, ValidateTieFromIndex<N>>();
|
||||
test_simple<N, GetFirst, ValidateGetFirstFromIndex<N>>();
|
||||
test_simple<N, Multiply, ValidateMultiplyFromIndex<N>>();
|
||||
|
||||
test_non_simple<N, MakeTuple, ValidateTupleFromIndex<N>>();
|
||||
test_non_simple<N, Tie, ValidateTieFromIndex<N>>();
|
||||
test_non_simple<N, GetFirst, ValidateGetFirstFromIndex<N>>();
|
||||
test_non_simple<N, Multiply, ValidateMultiplyFromIndex<N>>();
|
||||
|
||||
// Test with view that doesn't support const begin()
|
||||
using ViewWithNoConstBegin = std::ranges::adjacent_transform_view<NoConstBeginView, MakeTuple, N>;
|
||||
static_assert(HasBegin<ViewWithNoConstBegin>);
|
||||
static_assert(!HasConstBegin<ViewWithNoConstBegin>);
|
||||
|
||||
using OnlyNonConstView = std::ranges::adjacent_transform_view<NonSimpleCommon, OnlyNonConstFn, N>;
|
||||
static_assert(HasBegin<OnlyNonConstView>);
|
||||
static_assert(!HasConstBegin<OnlyNonConstView>);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// adjacent_transform_view() = default;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
constexpr int buff[] = {1, 2, 3, 4, 5};
|
||||
|
||||
struct DefaultConstructibleView : std::ranges::view_base {
|
||||
constexpr DefaultConstructibleView() : begin_(buff), end_(buff + std::ranges::size(buff)) {}
|
||||
constexpr int const* begin() const { return begin_; }
|
||||
constexpr int const* end() const { return end_; }
|
||||
|
||||
private:
|
||||
int const* begin_;
|
||||
int const* end_;
|
||||
};
|
||||
|
||||
struct NoDefaultCtrView : std::ranges::view_base {
|
||||
NoDefaultCtrView() = delete;
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
static_assert(
|
||||
std::is_default_constructible_v<std::ranges::adjacent_transform_view<DefaultConstructibleView, MakeTuple, 1>>);
|
||||
static_assert(std::is_default_constructible_v<std::ranges::adjacent_transform_view<DefaultConstructibleView, Tie, 2>>);
|
||||
static_assert(
|
||||
std::is_default_constructible_v<std::ranges::adjacent_transform_view<DefaultConstructibleView, GetFirst, 3>>);
|
||||
static_assert(!std::is_default_constructible_v<std::ranges::adjacent_transform_view<NoDefaultCtrView, MakeTuple, 1>>);
|
||||
static_assert(!std::is_default_constructible_v<std::ranges::adjacent_transform_view<NoDefaultCtrView, Tie, 2>>);
|
||||
static_assert(!std::is_default_constructible_v<std::ranges::adjacent_transform_view<NoDefaultCtrView, GetFirst, 3>>);
|
||||
|
||||
template <std::size_t N, class Fn, class Validator>
|
||||
constexpr void test() {
|
||||
{
|
||||
using View = std::ranges::adjacent_transform_view<DefaultConstructibleView, Fn, N>;
|
||||
View v = View(); // the default constructor is not explicit
|
||||
assert(v.size() == std::ranges::size(buff) - (N - 1));
|
||||
Validator validator{};
|
||||
auto it = v.begin();
|
||||
validator(buff, *it, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple, ValidateTupleFromIndex<N>>();
|
||||
test<N, Tie, ValidateTieFromIndex<N>>();
|
||||
test<N, GetFirst, ValidateGetFirstFromIndex<N>>();
|
||||
test<N, Multiply, ValidateMultiplyFromIndex<N>>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// constexpr explicit adjacent_transform_view(View, F)
|
||||
|
||||
#include <numeric>
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
|
||||
#include "../range_adaptor_types.h"
|
||||
#include "helpers.h"
|
||||
|
||||
template <class T>
|
||||
void conversion_test(T);
|
||||
|
||||
template <class T, class... Args>
|
||||
concept implicitly_constructible_from = requires(Args&&... args) { conversion_test<T>({std::move(args)...}); };
|
||||
|
||||
// test constructor is explicit
|
||||
static_assert(
|
||||
std::constructible_from<std::ranges::adjacent_transform_view<SimpleCommon, MakeTuple, 1>, SimpleCommon, MakeTuple>);
|
||||
static_assert(!implicitly_constructible_from<std::ranges::adjacent_transform_view<SimpleCommon, MakeTuple, 1>,
|
||||
SimpleCommon,
|
||||
MakeTuple>);
|
||||
|
||||
static_assert(std::constructible_from<std::ranges::adjacent_transform_view<SimpleCommon, Tie, 5>, SimpleCommon, Tie>);
|
||||
static_assert(
|
||||
!implicitly_constructible_from<std::ranges::adjacent_transform_view<SimpleCommon, Tie, 5>, SimpleCommon, Tie>);
|
||||
|
||||
struct MoveAwareView : std::ranges::view_base {
|
||||
int moves = 0;
|
||||
constexpr MoveAwareView() = default;
|
||||
constexpr MoveAwareView(MoveAwareView&& other) : moves(other.moves + 1) { other.moves = 1; }
|
||||
constexpr MoveAwareView& operator=(MoveAwareView&& other) {
|
||||
moves = other.moves + 1;
|
||||
other.moves = 0;
|
||||
return *this;
|
||||
}
|
||||
constexpr const int* begin() const { return &moves; }
|
||||
constexpr const int* end() const { return &moves + 1; }
|
||||
};
|
||||
|
||||
template <class View, class Fn, std::size_t N, class Validator>
|
||||
constexpr void test() {
|
||||
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
std::ranges::adjacent_transform_view<View, Fn, N> v{View{buffer}, Fn{}};
|
||||
Validator validator{};
|
||||
auto it = v.begin();
|
||||
validator(buffer, *it, 0);
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn, class Validator>
|
||||
constexpr void test() {
|
||||
{
|
||||
// arguments are moved once
|
||||
MoveAwareView mv;
|
||||
std::ranges::adjacent_transform_view<MoveAwareView, GetFirst, N> v{std::move(mv), GetFirst{}};
|
||||
auto& first = *v.begin();
|
||||
// one move from the local variable to parameter, one move from parameter to adjacent_view, and one move to adjacent_transform_view
|
||||
assert(first == 3);
|
||||
}
|
||||
|
||||
test<ForwardSizedView, Fn, N, Validator>();
|
||||
test<BidiCommonView, Fn, N, Validator>();
|
||||
test<SizedRandomAccessView, Fn, N, Validator>();
|
||||
test<ContiguousCommonView, Fn, N, Validator>();
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple, ValidateTupleFromIndex<N>>();
|
||||
test<N, Tie, ValidateTieFromIndex<N>>();
|
||||
test<N, GetFirst, ValidateGetFirstFromIndex<N>>();
|
||||
test<N, Multiply, ValidateMultiplyFromIndex<N>>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,183 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// constexpr auto end()
|
||||
// constexpr auto end() const requires range<const InnerView> &&
|
||||
// regular_invocable<const F&, REPEAT(range_reference_t<const V>, N)...>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../range_adaptor_types.h"
|
||||
#include "helpers.h"
|
||||
|
||||
template <class T>
|
||||
concept HasConstEnd = requires(const T& ct) { ct.end(); };
|
||||
|
||||
template <class T>
|
||||
concept HasEnd = requires(T& t) { t.end(); };
|
||||
|
||||
struct NoConstEndView : std::ranges::view_base {
|
||||
int* begin();
|
||||
int* end();
|
||||
};
|
||||
|
||||
struct OnlyNonConstFn {
|
||||
template <class... T>
|
||||
requires((!std::is_const_v<std::remove_reference_t<T>>) && ...)
|
||||
int operator()(T&&...) const;
|
||||
};
|
||||
|
||||
template <class R, class Fn, std::size_t N>
|
||||
constexpr void test_one() {
|
||||
{
|
||||
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
std::ranges::adjacent_transform_view<R, Fn, N> v{R{buffer}, Fn{}};
|
||||
|
||||
auto it = v.begin();
|
||||
auto cit = std::as_const(v).begin();
|
||||
auto endIt = v.end();
|
||||
auto cendIt = std::as_const(v).end();
|
||||
assert(it != endIt);
|
||||
assert(cit != cendIt);
|
||||
assert(it + (8 - (N - 1)) == endIt);
|
||||
assert(cit + (8 - (N - 1)) == cendIt);
|
||||
}
|
||||
{
|
||||
// empty range
|
||||
std::array<int, 0> buffer = {};
|
||||
std::ranges::adjacent_transform_view<R, Fn, N> v{R{buffer.data(), 0}, Fn{}};
|
||||
auto it = v.begin();
|
||||
auto cit = std::as_const(v).begin();
|
||||
auto endIt = v.end();
|
||||
auto cendIt = std::as_const(v).end();
|
||||
assert(it == endIt);
|
||||
assert(cit == cendIt);
|
||||
}
|
||||
if constexpr (N > 2) {
|
||||
// N greater than range size
|
||||
int buffer[2] = {1, 2};
|
||||
std::ranges::adjacent_transform_view<R, Fn, N> v{R{buffer}, Fn{}};
|
||||
auto it = v.begin();
|
||||
auto cit = std::as_const(v).begin();
|
||||
auto endIt = v.end();
|
||||
auto cendIt = std::as_const(v).end();
|
||||
assert(it == endIt);
|
||||
assert(cit == cendIt);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test_simple_common_types() {
|
||||
using NonConstView = std::ranges::adjacent_transform_view<SimpleCommon, Fn, N>;
|
||||
using ConstView = const NonConstView;
|
||||
|
||||
static_assert(std::ranges::common_range<NonConstView>);
|
||||
static_assert(std::ranges::common_range<ConstView>);
|
||||
|
||||
// non-const end always exists and returns iterator<false>
|
||||
static_assert(!std::is_same_v<std::ranges::sentinel_t<NonConstView>, std::ranges::sentinel_t<ConstView>>);
|
||||
|
||||
test_one<SimpleCommon, Fn, N>();
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test_simple_non_common_types() {
|
||||
using NonConstView = std::ranges::adjacent_transform_view<SimpleNonCommon, Fn, N>;
|
||||
using ConstView = const NonConstView;
|
||||
|
||||
static_assert(!std::ranges::common_range<NonConstView>);
|
||||
static_assert(!std::ranges::common_range<ConstView>);
|
||||
|
||||
// non-const end always exists and returns sentinel<false>
|
||||
static_assert(!std::is_same_v<std::ranges::sentinel_t<NonConstView>, std::ranges::sentinel_t<ConstView>>);
|
||||
|
||||
test_one<SimpleNonCommon, Fn, N>();
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test_non_simple_common_types() {
|
||||
using NonConstView = std::ranges::adjacent_transform_view<NonSimpleCommon, Fn, N>;
|
||||
using ConstView = const NonConstView;
|
||||
|
||||
static_assert(std::ranges::common_range<NonConstView>);
|
||||
static_assert(std::ranges::common_range<ConstView>);
|
||||
static_assert(!std::is_same_v<std::ranges::sentinel_t<NonConstView>, std::ranges::sentinel_t<ConstView>>);
|
||||
|
||||
test_one<NonSimpleCommon, Fn, N>();
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test_non_simple_non_common_types() {
|
||||
using NonConstView = std::ranges::adjacent_transform_view<NonSimpleNonCommon, Fn, N>;
|
||||
using ConstView = const NonConstView;
|
||||
|
||||
static_assert(!std::ranges::common_range<NonConstView>);
|
||||
static_assert(!std::ranges::common_range<ConstView>);
|
||||
static_assert(!std::is_same_v<std::ranges::sentinel_t<NonConstView>, std::ranges::sentinel_t<ConstView>>);
|
||||
|
||||
test_one<NonSimpleNonCommon, Fn, N>();
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test_forward_only() {
|
||||
using NonConstView = std::ranges::adjacent_transform_view<NonSimpleForwardSizedNonCommon, Fn, N>;
|
||||
using ConstView = const NonConstView;
|
||||
|
||||
static_assert(!std::ranges::common_range<NonConstView>);
|
||||
static_assert(!std::ranges::common_range<ConstView>);
|
||||
static_assert(!std::is_same_v<std::ranges::sentinel_t<NonConstView>, std::ranges::sentinel_t<ConstView>>);
|
||||
|
||||
test_one<NonSimpleForwardSizedNonCommon, Fn, N>();
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test() {
|
||||
test_simple_common_types<N, Fn>();
|
||||
test_simple_non_common_types<N, Fn>();
|
||||
test_non_simple_common_types<N, Fn>();
|
||||
test_non_simple_non_common_types<N, Fn>();
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple>();
|
||||
test<N, Tie>();
|
||||
test<N, GetFirst>();
|
||||
test<N, Multiply>();
|
||||
|
||||
// Test with view that doesn't support const end()
|
||||
using ViewWithNoConstBegin = std::ranges::adjacent_transform_view<NoConstEndView, MakeTuple, N>;
|
||||
static_assert(HasEnd<ViewWithNoConstBegin>);
|
||||
static_assert(!HasConstEnd<ViewWithNoConstBegin>);
|
||||
|
||||
using OnlyNonConstView = std::ranges::adjacent_transform_view<NonSimpleCommon, OnlyNonConstFn, N>;
|
||||
static_assert(HasEnd<OnlyNonConstView>);
|
||||
static_assert(!HasConstEnd<OnlyNonConstView>);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// Some basic examples of how adjacent_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 <cstddef>
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
constexpr bool test() {
|
||||
std::vector v = {1, 2, 3, 4};
|
||||
std::vector expected = {2, 6, 12};
|
||||
|
||||
{
|
||||
auto expected_index = 0;
|
||||
for (auto x : v | std::views::adjacent_transform<2>(std::multiplies())) {
|
||||
assert(x == expected[expected_index++]);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto expected_index = 0;
|
||||
for (auto x : v | std::views::pairwise_transform(std::multiplies())) {
|
||||
assert(x == expected[expected_index++]);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ADJACENT_TRANSFORM_HELPERS_H
|
||||
#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ADJACENT_TRANSFORM_HELPERS_H
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <numeric>
|
||||
#include <tuple>
|
||||
|
||||
// intentionally not using meta programming for the expected tuple types
|
||||
|
||||
struct Multiply {
|
||||
template <class... Ts>
|
||||
constexpr auto operator()(Ts... args) const {
|
||||
return (1 * ... * args);
|
||||
}
|
||||
};
|
||||
|
||||
struct MakeTuple {
|
||||
constexpr auto operator()(auto&&... args) const { return std::make_tuple(std::forward<decltype(args)>(args)...); }
|
||||
};
|
||||
|
||||
struct Tie {
|
||||
constexpr auto operator()(auto&&... args) const { return std::tie(std::forward<decltype(args)>(args)...); }
|
||||
};
|
||||
|
||||
struct GetFirst {
|
||||
constexpr decltype(auto) operator()(auto&& first, auto&&...) const { return std::forward<decltype(first)>(first); }
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct ValidateTieFromIndex {
|
||||
constexpr void operator()(auto&& buffer, auto&& tuple, std::size_t idx) const {
|
||||
assert(&std::get<0>(tuple) == &buffer[idx]);
|
||||
if constexpr (N >= 2)
|
||||
assert(&std::get<1>(tuple) == &buffer[idx + 1]);
|
||||
if constexpr (N >= 3)
|
||||
assert(&std::get<2>(tuple) == &buffer[idx + 2]);
|
||||
if constexpr (N >= 4)
|
||||
assert(&std::get<3>(tuple) == &buffer[idx + 3]);
|
||||
if constexpr (N >= 5)
|
||||
assert(&std::get<4>(tuple) == &buffer[idx + 4]);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct ValidateTupleFromIndex {
|
||||
constexpr void operator()(auto&& buffer, auto&& tuple, std::size_t idx) const {
|
||||
assert(std::get<0>(tuple) == buffer[idx]);
|
||||
if constexpr (N >= 2)
|
||||
assert(std::get<1>(tuple) == buffer[idx + 1]);
|
||||
if constexpr (N >= 3)
|
||||
assert(std::get<2>(tuple) == buffer[idx + 2]);
|
||||
if constexpr (N >= 4)
|
||||
assert(std::get<3>(tuple) == buffer[idx + 3]);
|
||||
if constexpr (N >= 5)
|
||||
assert(std::get<4>(tuple) == buffer[idx + 4]);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct ValidateGetFirstFromIndex {
|
||||
constexpr void operator()(auto&& buffer, auto&& result, std::size_t idx) const { assert(&result == &buffer[idx]); }
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct ValidateMultiplyFromIndex {
|
||||
constexpr void operator()(auto&& buffer, auto&& result, std::size_t idx) const {
|
||||
auto expected = std::accumulate(buffer + idx, buffer + idx + N, 1, std::multiplies<>());
|
||||
assert(result == expected);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N, class T>
|
||||
struct ExpectedTupleType;
|
||||
|
||||
template <class T>
|
||||
struct ExpectedTupleType<1, T> {
|
||||
using type = std::tuple<T>;
|
||||
};
|
||||
template <class T>
|
||||
struct ExpectedTupleType<2, T> {
|
||||
using type = std::tuple<T, T>;
|
||||
};
|
||||
template <class T>
|
||||
struct ExpectedTupleType<3, T> {
|
||||
using type = std::tuple<T, T, T>;
|
||||
};
|
||||
template <class T>
|
||||
struct ExpectedTupleType<4, T> {
|
||||
using type = std::tuple<T, T, T, T>;
|
||||
};
|
||||
template <class T>
|
||||
struct ExpectedTupleType<5, T> {
|
||||
using type = std::tuple<T, T, T, T, T>;
|
||||
};
|
||||
|
||||
template <std::size_t N, class T>
|
||||
using expectedTupleType = typename ExpectedTupleType<N, T>::type;
|
||||
|
||||
#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ADJACENT_TRANSFORM_HELPERS_H
|
||||
@ -0,0 +1,164 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// constexpr iterator& operator+=(difference_type x)
|
||||
// requires random_access_range<Base>;
|
||||
// constexpr iterator& operator-=(difference_type x)
|
||||
// requires random_access_range<Base>;
|
||||
// friend constexpr iterator operator+(const iterator& i, difference_type n)
|
||||
// requires random_access_range<Base>;
|
||||
// friend constexpr iterator operator+(difference_type n, const iterator& i)
|
||||
// requires random_access_range<Base>;
|
||||
// friend constexpr iterator operator-(const iterator& i, difference_type n)
|
||||
// requires random_access_range<Base>;
|
||||
// friend constexpr difference_type operator-(const iterator& x, const iterator& y)
|
||||
// requires sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>;
|
||||
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
|
||||
template <class T, class U>
|
||||
concept canPlusEqual = requires(T& t, U& u) { t += u; };
|
||||
|
||||
template <class T, class U>
|
||||
concept canMinusEqual = requires(T& t, U& u) { t -= u; };
|
||||
|
||||
template <class R, class Fn, std::size_t N, class Validator>
|
||||
constexpr void test() {
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
Validator validator{};
|
||||
|
||||
R rng{buffer};
|
||||
{
|
||||
// operator+(x, n) and operator+=
|
||||
std::ranges::adjacent_transform_view<R, Fn, N> v(rng, Fn{});
|
||||
auto it1 = v.begin();
|
||||
|
||||
validator(buffer, *it1, 0);
|
||||
|
||||
auto it2 = it1 + 3;
|
||||
validator(buffer, *it2, 3);
|
||||
|
||||
auto it3 = 3 + it1;
|
||||
validator(buffer, *it3, 3);
|
||||
|
||||
it1 += 3;
|
||||
assert(it1 == it2);
|
||||
validator(buffer, *it1, 3);
|
||||
}
|
||||
|
||||
{
|
||||
// operator-(x, n) and operator-=
|
||||
std::ranges::adjacent_transform_view<R, Fn, N> v(rng, Fn{});
|
||||
auto it1 = v.end();
|
||||
|
||||
auto it2 = it1 - 3;
|
||||
validator(buffer, *it2, 7 - N);
|
||||
|
||||
it1 -= 3;
|
||||
assert(it1 == it2);
|
||||
validator(buffer, *it1, 7 - N);
|
||||
}
|
||||
|
||||
{
|
||||
// operator-(x, y)
|
||||
std::ranges::adjacent_transform_view<R, Fn, N> v(rng, Fn{});
|
||||
assert((v.end() - v.begin()) == (10 - N));
|
||||
|
||||
auto it1 = v.begin() + 2;
|
||||
auto it2 = v.end() - 1;
|
||||
assert((it1 - it2) == static_cast<long>(N) - 7);
|
||||
}
|
||||
|
||||
{
|
||||
// empty range
|
||||
std::ranges::adjacent_transform_view<R, Fn, N> v(R{buffer, 0}, Fn{});
|
||||
assert((v.end() - v.begin()) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
// N > size of range
|
||||
std::ranges::adjacent_transform_view<R, Fn, 3> v(R{buffer, 2}, Fn{});
|
||||
assert((v.end() - v.begin()) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn, class Validator>
|
||||
constexpr void test() {
|
||||
test<ContiguousCommonView, Fn, N, Validator>();
|
||||
test<SimpleCommonRandomAccessSized, Fn, N, Validator>();
|
||||
|
||||
{
|
||||
// Non random access but sized sentinel
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
using View = std::ranges::adjacent_transform_view<ForwardSizedView, Fn, N>;
|
||||
using Iter = std::ranges::iterator_t<View>;
|
||||
using Diff = std::iter_difference_t<Iter>;
|
||||
|
||||
static_assert(!std::invocable<std::plus<>, Iter, Diff>);
|
||||
static_assert(!std::invocable<std::plus<>, Diff, Iter>);
|
||||
static_assert(!canPlusEqual<Iter, Diff>);
|
||||
static_assert(!std::invocable<std::minus<>, Iter, Diff>);
|
||||
static_assert(!canMinusEqual<Iter, Diff>);
|
||||
static_assert(std::invocable<std::minus<>, Iter, Iter>);
|
||||
|
||||
View v(ForwardSizedView{buffer}, Fn{});
|
||||
auto it1 = v.begin();
|
||||
auto it2 = v.end();
|
||||
assert((it2 - it1) == (10 - N));
|
||||
}
|
||||
|
||||
{
|
||||
// Non random access and non-sized sentinel
|
||||
using View = std::ranges::adjacent_transform_view<SimpleNonCommonNonRandom, Fn, N>;
|
||||
using Iter = std::ranges::iterator_t<View>;
|
||||
using Diff = std::iter_difference_t<Iter>;
|
||||
|
||||
static_assert(!std::invocable<std::plus<>, Iter, Diff>);
|
||||
static_assert(!std::invocable<std::plus<>, Diff, Iter>);
|
||||
static_assert(!canPlusEqual<Iter, Diff>);
|
||||
static_assert(!std::invocable<std::minus<>, Iter, Diff>);
|
||||
static_assert(!canMinusEqual<Iter, Diff>);
|
||||
static_assert(!std::invocable<std::minus<>, Iter, Iter>);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple, ValidateTupleFromIndex<N>>();
|
||||
test<N, Tie, ValidateTieFromIndex<N>>();
|
||||
test<N, GetFirst, ValidateGetFirstFromIndex<N>>();
|
||||
test<N, Multiply, ValidateMultiplyFromIndex<N>>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,162 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// friend constexpr bool operator==(const iterator& x, const iterator& y);
|
||||
// friend constexpr bool operator<(const iterator& x, const iterator& y)
|
||||
// requires random_access_range<Base>;
|
||||
// friend constexpr bool operator>(const iterator& x, const iterator& y)
|
||||
// requires random_access_range<Base>;
|
||||
// friend constexpr bool operator<=(const iterator& x, const iterator& y)
|
||||
// requires random_access_range<Base>;
|
||||
// friend constexpr bool operator>=(const iterator& x, const iterator& y)
|
||||
// requires random_access_range<Base>;
|
||||
// friend constexpr auto operator<=>(const iterator& x, const iterator& y)
|
||||
// requires random_access_range<Base> &&
|
||||
// three_way_comparable<inner-iterator<Const>>;
|
||||
|
||||
#include <ranges>
|
||||
#include <compare>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "test_range.h"
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
|
||||
constexpr void compareOperatorTest(auto&& iter1, auto&& iter2) {
|
||||
assert(!(iter1 < iter1));
|
||||
assert(iter1 < iter2);
|
||||
assert(!(iter2 < iter1));
|
||||
assert(iter1 <= iter1);
|
||||
assert(iter1 <= iter2);
|
||||
assert(!(iter2 <= iter1));
|
||||
assert(!(iter1 > iter1));
|
||||
assert(!(iter1 > iter2));
|
||||
assert(iter2 > iter1);
|
||||
assert(iter1 >= iter1);
|
||||
assert(!(iter1 >= iter2));
|
||||
assert(iter2 >= iter1);
|
||||
assert(iter1 == iter1);
|
||||
assert(!(iter1 == iter2));
|
||||
assert(iter2 == iter2);
|
||||
assert(!(iter1 != iter1));
|
||||
assert(iter1 != iter2);
|
||||
assert(!(iter2 != iter2));
|
||||
}
|
||||
|
||||
constexpr void inequalityOperatorsDoNotExistTest(auto&& iter1, auto&& iter2) {
|
||||
using Iter1 = decltype(iter1);
|
||||
using Iter2 = decltype(iter2);
|
||||
static_assert(!std::is_invocable_v<std::less<>, Iter1, Iter2>);
|
||||
static_assert(!std::is_invocable_v<std::less_equal<>, Iter1, Iter2>);
|
||||
static_assert(!std::is_invocable_v<std::greater<>, Iter1, Iter2>);
|
||||
static_assert(!std::is_invocable_v<std::greater_equal<>, Iter1, Iter2>);
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test() {
|
||||
{
|
||||
// Test a new-school iterator with operator<=>; the iterator should also have operator<=>.
|
||||
using It = three_way_contiguous_iterator<int*>;
|
||||
using SubRange = std::ranges::subrange<It>;
|
||||
static_assert(std::three_way_comparable<It>);
|
||||
using R = std::ranges::adjacent_transform_view<SubRange, Fn, N>;
|
||||
static_assert(std::three_way_comparable<std::ranges::iterator_t<R>>);
|
||||
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
auto r = R{SubRange(It(buffer), It(buffer + 8)), Fn{}};
|
||||
auto iter1 = r.begin();
|
||||
auto iter2 = iter1 + 1;
|
||||
|
||||
compareOperatorTest(iter1, iter2);
|
||||
|
||||
assert((iter1 <=> iter2) == std::strong_ordering::less);
|
||||
assert((iter1 <=> iter1) == std::strong_ordering::equal);
|
||||
assert((iter2 <=> iter1) == std::strong_ordering::greater);
|
||||
}
|
||||
|
||||
{
|
||||
// Test an old-school iterator with no operator<=>; the adjacent_transform iterator shouldn't have
|
||||
// operator<=> either.
|
||||
using It = random_access_iterator<int*>;
|
||||
using SubRange = std::ranges::subrange<It>;
|
||||
static_assert(!std::three_way_comparable<It>);
|
||||
using R = std::ranges::adjacent_transform_view<SubRange, Fn, N>;
|
||||
static_assert(!std::three_way_comparable<std::ranges::iterator_t<R>>);
|
||||
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
auto r = R{SubRange(It(buffer), It(buffer + 8)), Fn{}};
|
||||
auto iter1 = r.begin();
|
||||
auto iter2 = iter1 + 1;
|
||||
|
||||
compareOperatorTest(iter1, iter2);
|
||||
}
|
||||
|
||||
{
|
||||
// non random_access_range
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
std::ranges::adjacent_transform_view<BidiCommonView, Fn, N> v(BidiCommonView{buffer}, Fn{});
|
||||
using View = decltype(v);
|
||||
static_assert(!std::ranges::random_access_range<View>);
|
||||
|
||||
auto it1 = v.begin();
|
||||
auto it2 = v.end();
|
||||
assert(it1 != it2);
|
||||
|
||||
// advance it1 to the end
|
||||
std::ranges::advance(it1, 9 - N);
|
||||
assert(it1 == it2);
|
||||
|
||||
inequalityOperatorsDoNotExistTest(it1, it2);
|
||||
}
|
||||
|
||||
{
|
||||
// empty range
|
||||
auto v = std::views::empty<int> | std::views::adjacent_transform<N>(Fn{});
|
||||
auto it1 = v.begin();
|
||||
auto it2 = v.end();
|
||||
assert(it1 == it2);
|
||||
}
|
||||
|
||||
{
|
||||
// N > size of range
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
auto v = std::ranges::adjacent_transform_view<ContiguousCommonView, Fn, 10>(ContiguousCommonView{buffer}, Fn{});
|
||||
auto it1 = v.begin();
|
||||
auto it2 = v.end();
|
||||
assert(it1 == it2);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple>();
|
||||
test<N, Tie>();
|
||||
test<N, GetFirst>();
|
||||
test<N, Multiply>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// iterator() = default;
|
||||
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
|
||||
struct IterDefaultCtrView : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test() {
|
||||
using View = std::ranges::adjacent_transform_view<IterDefaultCtrView, MakeTuple, N>;
|
||||
using Iter = std::ranges::iterator_t<View>;
|
||||
{
|
||||
Iter iter1;
|
||||
Iter iter2 = {};
|
||||
assert(iter1 == iter2);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple>();
|
||||
test<N, Tie>();
|
||||
test<N, GetFirst>();
|
||||
test<N, Multiply>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// constexpr iterator(iterator<!Const> i)
|
||||
// requires Const && convertible_to<inner-iterator<false>, inner-iterator<Const>>;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#include <tuple>
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
|
||||
using ConstIterIncompatibleView =
|
||||
BasicView<forward_iterator<int*>,
|
||||
forward_iterator<int*>,
|
||||
random_access_iterator<const int*>,
|
||||
random_access_iterator<const int*>>;
|
||||
static_assert(!std::convertible_to<std::ranges::iterator_t<ConstIterIncompatibleView>,
|
||||
std::ranges::iterator_t<const ConstIterIncompatibleView>>);
|
||||
|
||||
template <std::size_t N, class Fn, class Validator>
|
||||
constexpr void test() {
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
Validator validator{};
|
||||
{
|
||||
std::ranges::adjacent_transform_view<NonSimpleCommon, Fn, N> v(NonSimpleCommon{buffer}, Fn{});
|
||||
auto iter1 = v.begin();
|
||||
std::ranges::iterator_t<const decltype(v)> iter2 = iter1;
|
||||
|
||||
static_assert(!std::is_same_v<decltype(iter1), decltype(iter2)>);
|
||||
// We cannot create a non-const iterator from a const iterator.
|
||||
static_assert(!std::constructible_from<decltype(iter1), decltype(iter2)>);
|
||||
|
||||
assert(iter1 == iter2);
|
||||
|
||||
validator(buffer, *iter1, 0);
|
||||
validator(buffer, *iter2, 0);
|
||||
}
|
||||
|
||||
{
|
||||
// underlying non-const to const not convertible
|
||||
std::ranges::adjacent_transform_view<ConstIterIncompatibleView, Tie, N> v(ConstIterIncompatibleView{buffer}, Tie{});
|
||||
auto iter1 = v.begin();
|
||||
auto iter2 = std::as_const(v).begin();
|
||||
|
||||
static_assert(!std::is_same_v<decltype(iter1), decltype(iter2)>);
|
||||
|
||||
static_assert(!std::constructible_from<decltype(iter1), decltype(iter2)>);
|
||||
static_assert(!std::constructible_from<decltype(iter2), decltype(iter1)>);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple, ValidateTupleFromIndex<N>>();
|
||||
test<N, Tie, ValidateTieFromIndex<N>>();
|
||||
test<N, GetFirst, ValidateGetFirstFromIndex<N>>();
|
||||
test<N, Multiply, ValidateMultiplyFromIndex<N>>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<5>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,100 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// constexpr iterator& operator--() requires bidirectional_range<Base>;
|
||||
// constexpr iterator operator--(int) requires bidirectional_range<Base>;
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
|
||||
template <class Iter>
|
||||
concept canDecrement = requires(Iter it) { --it; } || requires(Iter it) { it--; };
|
||||
|
||||
template <class R, class Fn, std::size_t N, class Validator>
|
||||
constexpr void test_one() {
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
Validator validator{};
|
||||
|
||||
auto v = R(buffer) | std::views::adjacent_transform<N>(Fn{});
|
||||
|
||||
auto it = v.begin();
|
||||
using Iter = decltype(it);
|
||||
|
||||
std::ranges::advance(it, v.end());
|
||||
|
||||
--it;
|
||||
validator(buffer, *it, 9 - N);
|
||||
|
||||
static_assert(std::is_same_v<decltype(--it), Iter&>);
|
||||
std::same_as<Iter&> decltype(auto) it_ref = --it;
|
||||
assert(&it_ref == &it);
|
||||
|
||||
validator(buffer, *it, 8 - N);
|
||||
|
||||
std::same_as<Iter> decltype(auto) tmp = it--;
|
||||
|
||||
validator(buffer, *tmp, 8 - N);
|
||||
validator(buffer, *it, 7 - N);
|
||||
|
||||
// Decrement to the beginning
|
||||
for (int i = 6 - N; i >= 0; --i) {
|
||||
--it;
|
||||
validator(buffer, *it, i);
|
||||
}
|
||||
assert(it == v.begin());
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn, class Validator>
|
||||
constexpr void test() {
|
||||
test_one<ContiguousNonCommonSized, Fn, N, Validator>();
|
||||
test_one<SimpleCommonRandomAccessSized, Fn, N, Validator>();
|
||||
test_one<BidiNonCommonView, Fn, N, Validator>();
|
||||
|
||||
// Non-bidirectional base range
|
||||
{
|
||||
using View = std::ranges::adjacent_transform_view<ForwardSizedView, Fn, N>;
|
||||
using Iter = std::ranges::iterator_t<View>;
|
||||
|
||||
static_assert(!canDecrement<Iter>);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple, ValidateTupleFromIndex<N>>();
|
||||
test<N, Tie, ValidateTieFromIndex<N>>();
|
||||
test<N, GetFirst, ValidateGetFirstFromIndex<N>>();
|
||||
test<N, Multiply, ValidateMultiplyFromIndex<N>>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
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, c++20
|
||||
|
||||
// constexpr decltype(auto) operator*() const noexcept(see below);
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <numeric>
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
|
||||
template <class Iter>
|
||||
concept DerefNoexcept = requires(const Iter iter) {
|
||||
{ *iter } noexcept;
|
||||
};
|
||||
|
||||
static_assert(DerefNoexcept<int*>);
|
||||
|
||||
struct NoExceptInvocable {
|
||||
int operator()(auto...) const noexcept;
|
||||
};
|
||||
|
||||
struct ThrowingInvocable {
|
||||
int operator()(auto...) const;
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
// Remarks: Let Is be the pack 0, 1, ..., (N - 1). The exception specification is equivalent to:
|
||||
// noexcept(invoke(*parent_->fun_, *std::get<Is>(inner_.current_)...))
|
||||
{
|
||||
using View = std::ranges::adjacent_transform_view<SimpleCommon, NoExceptInvocable, N>;
|
||||
static_assert(DerefNoexcept<std::ranges::iterator_t<View>>);
|
||||
}
|
||||
{
|
||||
using View = std::ranges::adjacent_transform_view<SimpleCommon, ThrowingInvocable, N>;
|
||||
static_assert(!DerefNoexcept<std::ranges::iterator_t<View>>);
|
||||
}
|
||||
{
|
||||
// underlying iter deref not noexcept
|
||||
static_assert(!DerefNoexcept<std::ranges::iterator_t<ForwardSizedView>>);
|
||||
using View = std::ranges::adjacent_transform_view<ForwardSizedView, NoExceptInvocable, N>;
|
||||
static_assert(!DerefNoexcept<std::ranges::iterator_t<View>>);
|
||||
}
|
||||
|
||||
{
|
||||
// make_tuple
|
||||
auto v = buffer | std::views::adjacent_transform<N>(MakeTuple{});
|
||||
std::same_as<expectedTupleType<N, int>> decltype(auto) res = *v.begin();
|
||||
ValidateTupleFromIndex<N>{}(buffer, res, 0);
|
||||
}
|
||||
|
||||
{
|
||||
// tie
|
||||
auto v = buffer | std::views::adjacent_transform<N>(Tie{});
|
||||
std::same_as<expectedTupleType<N, int&>> decltype(auto) res = *v.begin();
|
||||
ValidateTieFromIndex<N>{}(buffer, res, 0);
|
||||
}
|
||||
|
||||
{
|
||||
// get<0>
|
||||
auto v = buffer | std::views::adjacent_transform<N>(GetFirst{});
|
||||
std::same_as<int&> decltype(auto) res = *v.begin();
|
||||
assert(&res == &buffer[0]);
|
||||
}
|
||||
|
||||
{
|
||||
// Multiply
|
||||
auto v = buffer | std::views::adjacent_transform<N>(Multiply{});
|
||||
std::same_as<int> decltype(auto) res = *v.begin();
|
||||
auto expected = std::accumulate(buffer, buffer + N, 1, std::multiplies<>());
|
||||
assert(res == expected);
|
||||
}
|
||||
|
||||
{
|
||||
// operator* is const
|
||||
auto v = buffer | std::views::adjacent_transform<N>(GetFirst{});
|
||||
const auto it = v.begin();
|
||||
std::same_as<int&> decltype(auto) res = *it;
|
||||
assert(&res == &buffer[0]);
|
||||
}
|
||||
|
||||
{
|
||||
// underlying range with prvalue range_reference_t
|
||||
auto v = std::views::iota(0, 8) | std::views::adjacent_transform<N>(MakeTuple{});
|
||||
std::same_as<expectedTupleType<N, int>> decltype(auto) res = *v.begin();
|
||||
assert(std::get<0>(res) == 0);
|
||||
if constexpr (N >= 2)
|
||||
assert(std::get<1>(res) == 1);
|
||||
if constexpr (N >= 3)
|
||||
assert(std::get<2>(res) == 2);
|
||||
if constexpr (N >= 4)
|
||||
assert(std::get<3>(res) == 3);
|
||||
if constexpr (N >= 5)
|
||||
assert(std::get<4>(res) == 4);
|
||||
}
|
||||
|
||||
{
|
||||
// const-correctness
|
||||
const std::array bufferConst = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
auto v = bufferConst | std::views::adjacent_transform<N>(Tie{});
|
||||
std::same_as<expectedTupleType<N, const int&>> decltype(auto) res = *v.begin();
|
||||
assert(&std::get<0>(res) == &bufferConst[0]);
|
||||
if constexpr (N >= 2)
|
||||
assert(&std::get<1>(res) == &bufferConst[1]);
|
||||
if constexpr (N >= 3)
|
||||
assert(&std::get<2>(res) == &bufferConst[2]);
|
||||
if constexpr (N >= 4)
|
||||
assert(&std::get<3>(res) == &bufferConst[3]);
|
||||
if constexpr (N >= 5)
|
||||
assert(&std::get<4>(res) == &bufferConst[4]);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
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, c++20
|
||||
|
||||
// constexpr iterator& operator++();
|
||||
// constexpr iterator operator++(int);
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <numeric>
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
|
||||
template <class R, class Fn, std::size_t N, class Validator>
|
||||
constexpr void test() {
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
Validator validator{};
|
||||
|
||||
auto v = R(buffer) | std::views::adjacent_transform<N>(Fn{});
|
||||
auto it = v.begin();
|
||||
using Iter = decltype(it);
|
||||
|
||||
validator(buffer, *it, 0);
|
||||
|
||||
std::same_as<Iter&> decltype(auto) it_ref = ++it;
|
||||
assert(&it_ref == &it);
|
||||
|
||||
validator(buffer, *it, 1);
|
||||
|
||||
static_assert(std::is_same_v<decltype(it++), Iter>);
|
||||
auto original = it;
|
||||
std::same_as<Iter> decltype(auto) copy = it++;
|
||||
assert(original == copy);
|
||||
|
||||
validator(buffer, *copy, 1);
|
||||
validator(buffer, *it, 2);
|
||||
|
||||
// Increment to the end
|
||||
for (std::size_t i = 3; i != 9 - N; ++i) {
|
||||
++it;
|
||||
validator(buffer, *it, i);
|
||||
}
|
||||
|
||||
++it;
|
||||
assert(it == v.end());
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn, class Validator>
|
||||
constexpr void test() {
|
||||
test<ContiguousCommonView, Fn, N, Validator>();
|
||||
test<SimpleCommonRandomAccessSized, Fn, N, Validator>();
|
||||
test<BidiNonCommonView, Fn, N, Validator>();
|
||||
test<ForwardSizedView, Fn, N, Validator>();
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple, ValidateTupleFromIndex<N>>();
|
||||
test<N, Tie, ValidateTieFromIndex<N>>();
|
||||
test<N, GetFirst, ValidateGetFirstFromIndex<N>>();
|
||||
test<N, Multiply, ValidateMultiplyFromIndex<N>>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,144 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// Iterator traits and member typedefs in adjacent_transform_view::iterator.
|
||||
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_iterators.h"
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
|
||||
template <class T>
|
||||
struct DiffTypeIter : random_access_iterator<int*> {
|
||||
using value_type = int;
|
||||
using difference_type = T;
|
||||
|
||||
int& operator*() const;
|
||||
DiffTypeIter& operator++();
|
||||
DiffTypeIter operator++(int);
|
||||
friend constexpr bool operator==(DiffTypeIter, DiffTypeIter) = default;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct DiffTypeView : std::ranges::view_base {
|
||||
DiffTypeIter<T> begin() const;
|
||||
DiffTypeIter<T> end() const;
|
||||
};
|
||||
|
||||
struct Foo {};
|
||||
|
||||
struct ConstVeryDifferentRange {
|
||||
int* begin();
|
||||
int* end();
|
||||
|
||||
forward_iterator<double*> begin() const;
|
||||
forward_iterator<double*> end() const;
|
||||
};
|
||||
|
||||
template <class Fn, std::size_t N, class ExpectedValueType, bool IterCatShouldBeInput>
|
||||
void test() {
|
||||
int buffer[] = {1, 2, 3, 4};
|
||||
|
||||
{
|
||||
// Base contiguous range
|
||||
std::ranges::adjacent_transform_view<std::views::all_t<decltype((buffer))>, Fn, N> v(buffer, Fn{});
|
||||
using Iter = decltype(v.begin());
|
||||
using Cat = std::conditional_t<IterCatShouldBeInput, std::input_iterator_tag, std::random_access_iterator_tag>;
|
||||
|
||||
static_assert(std::is_same_v<typename Iter::iterator_concept, std::random_access_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename Iter::iterator_category, Cat>);
|
||||
static_assert(std::is_same_v<typename Iter::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::is_same_v<typename Iter::value_type, ExpectedValueType>);
|
||||
}
|
||||
|
||||
{
|
||||
// Base random access
|
||||
std::ranges::adjacent_transform_view<SizedRandomAccessView, Fn, N> v(SizedRandomAccessView{buffer}, Fn{});
|
||||
using Iter = decltype(v.begin());
|
||||
using Cat = std::conditional_t<IterCatShouldBeInput, std::input_iterator_tag, std::random_access_iterator_tag>;
|
||||
|
||||
static_assert(std::is_same_v<typename Iter::iterator_concept, std::random_access_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename Iter::iterator_category, Cat>);
|
||||
static_assert(std::is_same_v<typename Iter::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::is_same_v<typename Iter::value_type, ExpectedValueType>);
|
||||
}
|
||||
|
||||
{
|
||||
// Base bidirectional
|
||||
std::ranges::adjacent_transform_view<BidiCommonView, Fn, N> v(BidiCommonView{buffer}, Fn{});
|
||||
using Iter = decltype(v.begin());
|
||||
using Cat = std::conditional_t<IterCatShouldBeInput, std::input_iterator_tag, std::bidirectional_iterator_tag>;
|
||||
|
||||
static_assert(std::is_same_v<typename Iter::iterator_concept, std::bidirectional_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename Iter::iterator_category, Cat>);
|
||||
static_assert(std::is_same_v<typename Iter::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::is_same_v<typename Iter::value_type, ExpectedValueType>);
|
||||
}
|
||||
|
||||
{
|
||||
// Base forward
|
||||
std::ranges::adjacent_transform_view<ForwardSizedView, Fn, N> v(ForwardSizedView{buffer}, Fn{});
|
||||
using Iter = decltype(v.begin());
|
||||
using Cat = std::conditional_t<IterCatShouldBeInput, std::input_iterator_tag, std::forward_iterator_tag>;
|
||||
|
||||
static_assert(std::is_same_v<typename Iter::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename Iter::iterator_category, Cat>);
|
||||
static_assert(std::is_same_v<typename Iter::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::is_same_v<typename Iter::value_type, ExpectedValueType>);
|
||||
}
|
||||
|
||||
{
|
||||
// difference_type
|
||||
std::ranges::adjacent_transform_view<DiffTypeView<std::intptr_t>, Fn, N> v{DiffTypeView<std::intptr_t>{}, Fn{}};
|
||||
using Iter = decltype(v.begin());
|
||||
static_assert(std::is_same_v<typename Iter::difference_type, std::intptr_t>);
|
||||
}
|
||||
|
||||
{
|
||||
// const-iterator different from iterator
|
||||
auto v = ConstVeryDifferentRange{} | std::views::adjacent_transform<2>(MakeTuple{});
|
||||
using Iter = decltype(v.begin());
|
||||
using ConstIter = decltype(std::as_const(v).begin());
|
||||
|
||||
static_assert(std::is_same_v<typename Iter::iterator_concept, std::random_access_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename Iter::iterator_category, std::input_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename Iter::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::is_same_v<typename Iter::value_type, std::tuple<int, int>>);
|
||||
|
||||
static_assert(std::is_same_v<typename ConstIter::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename ConstIter::iterator_category, std::input_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename ConstIter::difference_type, std::ptrdiff_t>);
|
||||
static_assert(std::is_same_v<typename ConstIter::value_type, std::tuple<double, double>>);
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test<MakeTuple, 1, std::tuple<int>, true>();
|
||||
test<MakeTuple, 2, std::tuple<int, int>, true>();
|
||||
test<MakeTuple, 3, std::tuple<int, int, int>, true>();
|
||||
|
||||
test<Tie, 1, std::tuple<int&>, true>();
|
||||
test<Tie, 2, std::tuple<int&, int&>, true>();
|
||||
test<Tie, 3, std::tuple<int&, int&, int&>, true>();
|
||||
|
||||
test<GetFirst, 1, int, false>();
|
||||
test<GetFirst, 2, int, false>();
|
||||
test<GetFirst, 3, int, false>();
|
||||
|
||||
test<Multiply, 1, int, true>();
|
||||
test<Multiply, 2, int, true>();
|
||||
test<Multiply, 3, int, true>();
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
// UNSUPPORTED: no-exceptions
|
||||
|
||||
// If the invocation of any non-const member function of `iterator` exits via an
|
||||
// exception, the iterator acquires a singular value.
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
|
||||
struct ThrowOnDecrementIterator {
|
||||
int* it_;
|
||||
|
||||
using value_type = int;
|
||||
using difference_type = std::intptr_t;
|
||||
|
||||
ThrowOnDecrementIterator() = default;
|
||||
explicit ThrowOnDecrementIterator(int* it) : it_(it) {}
|
||||
|
||||
ThrowOnDecrementIterator& operator++() {
|
||||
++it_;
|
||||
return *this;
|
||||
}
|
||||
ThrowOnDecrementIterator operator++(int) {
|
||||
auto tmp = *this;
|
||||
++it_;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
ThrowOnDecrementIterator& operator--() { throw 5; }
|
||||
ThrowOnDecrementIterator operator--(int) { throw 5; }
|
||||
|
||||
int& operator*() const { return *it_; }
|
||||
|
||||
friend bool operator==(ThrowOnDecrementIterator const&, ThrowOnDecrementIterator const&) = default;
|
||||
};
|
||||
|
||||
struct ThrowOnIncrementView : IntBufferView {
|
||||
ThrowOnDecrementIterator begin() const { return ThrowOnDecrementIterator{buffer_}; }
|
||||
ThrowOnDecrementIterator end() const { return ThrowOnDecrementIterator{buffer_ + size_}; }
|
||||
};
|
||||
|
||||
template <std::size_t N, class Fn, class Validator>
|
||||
void test() {
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
Validator validator{};
|
||||
{
|
||||
// adjacent_transform_view iterator should be able to be destroyed after member function throws
|
||||
auto v = ThrowOnIncrementView{buffer} | std::views::adjacent_transform<N>(Fn{});
|
||||
auto it = v.begin();
|
||||
++it;
|
||||
try {
|
||||
--it;
|
||||
assert(false); // should not be reached as the above expression should throw.
|
||||
} catch (int e) {
|
||||
assert(e == 5);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// adjacent_transform_view iterator should be able to be assigned after member function throws
|
||||
auto v = ThrowOnIncrementView{buffer} | std::views::adjacent_transform<N>(Fn{});
|
||||
auto it = v.begin();
|
||||
++it;
|
||||
try {
|
||||
--it;
|
||||
assert(false); // should not be reached as the above expression should throw.
|
||||
} catch (int e) {
|
||||
assert(e == 5);
|
||||
}
|
||||
it = v.begin();
|
||||
validator(buffer, *it, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple, ValidateTupleFromIndex<N>>();
|
||||
test<N, Tie, ValidateTieFromIndex<N>>();
|
||||
test<N, GetFirst, ValidateGetFirstFromIndex<N>>();
|
||||
test<N, Multiply, ValidateMultiplyFromIndex<N>>();
|
||||
}
|
||||
|
||||
void test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// constexpr decltype(auto) operator[](difference_type n) const requires
|
||||
// all_random_access<Const, Views...>
|
||||
|
||||
#include <ranges>
|
||||
#include <cassert>
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test() {
|
||||
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
{
|
||||
// random_access_range
|
||||
std::ranges::adjacent_transform_view<SizedRandomAccessView, Fn, N> v(SizedRandomAccessView{buffer}, Fn{});
|
||||
auto it = v.begin();
|
||||
assert(it[0] == *it);
|
||||
assert(it[2] == *(it + 2));
|
||||
|
||||
static_assert(std::is_same_v<decltype(it[0]), decltype(*it)>);
|
||||
}
|
||||
|
||||
{
|
||||
// contiguous_range
|
||||
std::ranges::adjacent_transform_view<ContiguousCommonView, Fn, N> v(ContiguousCommonView{buffer}, Fn{});
|
||||
auto it = v.begin();
|
||||
assert(it[0] == *it);
|
||||
assert(it[2] == *(it + 2));
|
||||
|
||||
static_assert(std::is_same_v<decltype(it[0]), decltype(*it)>);
|
||||
}
|
||||
|
||||
{
|
||||
// non random_access_range
|
||||
std::ranges::adjacent_transform_view<BidiCommonView, Fn, N> v(BidiCommonView{buffer}, Fn{});
|
||||
auto iter = v.begin();
|
||||
const auto canSubscript = [](auto&& it) { return requires { it[0]; }; };
|
||||
static_assert(!canSubscript(iter));
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple>();
|
||||
test<N, Tie>();
|
||||
test<N, GetFirst>();
|
||||
test<N, Multiply>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,158 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// test if adjacent_transform_view models input_range, forward_range, bidirectional_range,
|
||||
// random_access_range, contiguous_range, common_range, sized_range
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "helpers.h"
|
||||
#include "../range_adaptor_types.h"
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void testConcept() {
|
||||
int buffer[3] = {1, 2, 3};
|
||||
{
|
||||
std::ranges::adjacent_transform_view<ContiguousCommonView, Fn, N> v(ContiguousCommonView{buffer}, Fn{});
|
||||
using View = decltype(v);
|
||||
static_assert(std::ranges::random_access_range<View>);
|
||||
static_assert(!std::ranges::contiguous_range<View>);
|
||||
static_assert(std::ranges::common_range<View>);
|
||||
static_assert(std::ranges::sized_range<View>);
|
||||
}
|
||||
|
||||
{
|
||||
std::ranges::adjacent_transform_view<ContiguousNonCommonView, Fn, N> v{ContiguousNonCommonView{buffer}, Fn{}};
|
||||
using View = decltype(v);
|
||||
static_assert(std::ranges::random_access_range<View>);
|
||||
static_assert(!std::ranges::contiguous_range<View>);
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
static_assert(!std::ranges::sized_range<View>);
|
||||
}
|
||||
|
||||
{
|
||||
std::ranges::adjacent_transform_view<ContiguousNonCommonSized, Fn, N> v{ContiguousNonCommonSized{buffer}, Fn{}};
|
||||
using View = decltype(v);
|
||||
static_assert(std::ranges::random_access_range<View>);
|
||||
static_assert(!std::ranges::contiguous_range<View>);
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
static_assert(std::ranges::sized_range<View>);
|
||||
}
|
||||
|
||||
{
|
||||
std::ranges::adjacent_transform_view<SizedRandomAccessView, Fn, N> v{SizedRandomAccessView{buffer}, Fn{}};
|
||||
using View = decltype(v);
|
||||
static_assert(std::ranges::random_access_range<View>);
|
||||
static_assert(!std::ranges::contiguous_range<View>);
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
static_assert(std::ranges::sized_range<View>);
|
||||
}
|
||||
|
||||
{
|
||||
std::ranges::adjacent_transform_view<NonSizedRandomAccessView, Fn, N> v{NonSizedRandomAccessView{buffer}, Fn{}};
|
||||
using View = decltype(v);
|
||||
static_assert(std::ranges::random_access_range<View>);
|
||||
static_assert(!std::ranges::contiguous_range<View>);
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
static_assert(!std::ranges::sized_range<View>);
|
||||
}
|
||||
|
||||
{
|
||||
std::ranges::adjacent_transform_view<BidiCommonView, Fn, N> v{BidiCommonView{buffer}, Fn{}};
|
||||
using View = decltype(v);
|
||||
static_assert(std::ranges::bidirectional_range<View>);
|
||||
static_assert(!std::ranges::random_access_range<View>);
|
||||
static_assert(std::ranges::common_range<View>);
|
||||
static_assert(!std::ranges::sized_range<View>);
|
||||
}
|
||||
|
||||
{
|
||||
std::ranges::adjacent_transform_view<BidiNonCommonView, Fn, N> v{BidiNonCommonView{buffer}, Fn{}};
|
||||
using View = decltype(v);
|
||||
static_assert(std::ranges::forward_range<View>);
|
||||
static_assert(std::ranges::bidirectional_range<View>);
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
static_assert(!std::ranges::sized_range<View>);
|
||||
}
|
||||
|
||||
{
|
||||
std::ranges::adjacent_transform_view<ForwardSizedView, Fn, N> v{ForwardSizedView{buffer}, Fn{}};
|
||||
using View = decltype(v);
|
||||
static_assert(std::ranges::forward_range<View>);
|
||||
static_assert(!std::ranges::bidirectional_range<View>);
|
||||
static_assert(std::ranges::common_range<View>);
|
||||
static_assert(std::ranges::sized_range<View>);
|
||||
}
|
||||
|
||||
{
|
||||
std::ranges::adjacent_transform_view<ForwardSizedNonCommon, Fn, N> v{ForwardSizedNonCommon{buffer}, Fn{}};
|
||||
using View = decltype(v);
|
||||
static_assert(std::ranges::forward_range<View>);
|
||||
static_assert(!std::ranges::bidirectional_range<View>);
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
static_assert(std::ranges::sized_range<View>);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr bool testConcept() {
|
||||
testConcept<N, MakeTuple>();
|
||||
testConcept<N, Tie>();
|
||||
testConcept<N, GetFirst>();
|
||||
testConcept<N, Multiply>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(testConcept<1>());
|
||||
static_assert(testConcept<2>());
|
||||
static_assert(testConcept<3>());
|
||||
static_assert(testConcept<5>());
|
||||
|
||||
using OutputIter = cpp17_output_iterator<int*>;
|
||||
static_assert(std::output_iterator<OutputIter, int>);
|
||||
|
||||
struct OutputView : std::ranges::view_base {
|
||||
OutputIter begin() const;
|
||||
sentinel_wrapper<OutputIter> end() const;
|
||||
};
|
||||
static_assert(std::ranges::output_range<OutputView, int>);
|
||||
static_assert(!std::ranges::input_range<OutputView>);
|
||||
|
||||
template <class T, class Fn, std::size_t N>
|
||||
concept adjacent_transform_viewable = requires { typename std::ranges::adjacent_transform_view<T, Fn, N>; };
|
||||
|
||||
static_assert(adjacent_transform_viewable<SimpleCommon, MakeTuple, 2>);
|
||||
static_assert(adjacent_transform_viewable<SimpleCommon, Tie, 2>);
|
||||
static_assert(adjacent_transform_viewable<SimpleCommon, GetFirst, 2>);
|
||||
|
||||
// output_range is not supported
|
||||
static_assert(!adjacent_transform_viewable<OutputView, MakeTuple, 2>);
|
||||
|
||||
// input only range is not supported
|
||||
static_assert(!adjacent_transform_viewable<InputCommonView, MakeTuple, 1>);
|
||||
static_assert(!adjacent_transform_viewable<InputNonCommonView, MakeTuple, 2>);
|
||||
|
||||
// Fn is not callble with the correct types
|
||||
struct FnNotCallable {
|
||||
void operator()() const {}
|
||||
};
|
||||
static_assert(!adjacent_transform_viewable<SimpleCommon, FnNotCallable, 2>);
|
||||
|
||||
// function that returns void is not supported
|
||||
struct FnReturnsVoid {
|
||||
template <class... Args>
|
||||
void operator()(Args&&...) const {}
|
||||
};
|
||||
static_assert(!adjacent_transform_viewable<SimpleCommon, FnReturnsVoid, 2>);
|
||||
@ -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, c++20
|
||||
|
||||
// sentinel() = default;
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
|
||||
#include "../helpers.h"
|
||||
|
||||
struct PODSentinel {
|
||||
bool b; // deliberately uninitialised
|
||||
|
||||
friend constexpr bool operator==(int*, const PODSentinel& s) { return s.b; }
|
||||
};
|
||||
|
||||
struct Range : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
PODSentinel end();
|
||||
};
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test() {
|
||||
{
|
||||
using R = std::ranges::adjacent_transform_view<Range, Fn, N>;
|
||||
using Sentinel = std::ranges::sentinel_t<R>;
|
||||
static_assert(!std::is_same_v<Sentinel, std::ranges::iterator_t<R>>);
|
||||
|
||||
std::ranges::iterator_t<R> it;
|
||||
|
||||
Sentinel s1;
|
||||
assert(it != s1); // PODSentinel.b is initialised to false
|
||||
|
||||
Sentinel s2 = {};
|
||||
assert(it != s2); // PODSentinel.b is initialised to false
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple>();
|
||||
test<N, Tie>();
|
||||
test<N, GetFirst>();
|
||||
test<N, Multiply>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,125 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// constexpr sentinel(sentinel<!Const> s);
|
||||
// requires Const && convertible_to<inner-sentinel<false>, inner-sentinel<Const>>;
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
|
||||
template <class T>
|
||||
struct convertible_sentinel_wrapper {
|
||||
explicit convertible_sentinel_wrapper() = default;
|
||||
constexpr convertible_sentinel_wrapper(const T& it) : it_(it) {}
|
||||
|
||||
template <class U>
|
||||
requires std::convertible_to<const U&, T>
|
||||
constexpr convertible_sentinel_wrapper(const convertible_sentinel_wrapper<U>& other) : it_(other.it_) {}
|
||||
|
||||
constexpr friend bool operator==(convertible_sentinel_wrapper const& self, const T& other) {
|
||||
return self.it_ == other;
|
||||
}
|
||||
T it_;
|
||||
};
|
||||
|
||||
struct SentinelConvertibleView : IntBufferView {
|
||||
using IntBufferView::IntBufferView;
|
||||
|
||||
constexpr int* begin() { return buffer_; }
|
||||
constexpr const int* begin() const { return buffer_; }
|
||||
constexpr convertible_sentinel_wrapper<int*> end() { return convertible_sentinel_wrapper<int*>(buffer_ + size_); }
|
||||
constexpr convertible_sentinel_wrapper<const int*> end() const {
|
||||
return convertible_sentinel_wrapper<const int*>(buffer_ + size_);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(!std::ranges::common_range<SentinelConvertibleView>);
|
||||
static_assert(std::convertible_to<std::ranges::sentinel_t<SentinelConvertibleView>,
|
||||
std::ranges::sentinel_t<SentinelConvertibleView const>>);
|
||||
static_assert(!simple_view<SentinelConvertibleView>);
|
||||
|
||||
struct SentinelNonConvertibleView : IntBufferView {
|
||||
using IntBufferView::IntBufferView;
|
||||
|
||||
constexpr int* begin() { return buffer_; }
|
||||
constexpr const int* begin() const { return buffer_; }
|
||||
constexpr sentinel_wrapper<int*> end() { return sentinel_wrapper<int*>(buffer_ + size_); }
|
||||
constexpr sentinel_wrapper<const int*> end() const { return sentinel_wrapper<const int*>(buffer_ + size_); }
|
||||
};
|
||||
|
||||
static_assert(!std::ranges::common_range<SentinelNonConvertibleView>);
|
||||
static_assert(!std::convertible_to<std::ranges::sentinel_t<SentinelNonConvertibleView>,
|
||||
std::ranges::sentinel_t<SentinelNonConvertibleView const>>);
|
||||
static_assert(!simple_view<SentinelNonConvertibleView>);
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test() {
|
||||
using View = std::ranges::adjacent_transform_view<SentinelConvertibleView, Fn, N>;
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
|
||||
using Sent = std::ranges::sentinel_t<View>;
|
||||
using ConstSent = std::ranges::sentinel_t<const View>;
|
||||
static_assert(!std::is_same_v<Sent, ConstSent>);
|
||||
|
||||
{
|
||||
// implicitly convertible
|
||||
static_assert(std::convertible_to<Sent, ConstSent>);
|
||||
}
|
||||
{
|
||||
// !Const
|
||||
static_assert(!std::convertible_to<ConstSent, Sent>);
|
||||
}
|
||||
{
|
||||
// !convertible_to<iterator_t<V>, iterator_t<Base>>
|
||||
using V2 = std::ranges::adjacent_transform_view<SentinelNonConvertibleView, Fn, N>;
|
||||
static_assert(!std::convertible_to<std::ranges::sentinel_t<V2>, std::ranges::sentinel_t<const V2>>);
|
||||
}
|
||||
|
||||
{
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
View v{SentinelConvertibleView{buffer}, Fn{}};
|
||||
Sent sent1 = v.end();
|
||||
ConstSent sent2 = sent1;
|
||||
|
||||
assert(v.begin() != sent2);
|
||||
assert(std::as_const(v).begin() != sent2);
|
||||
assert(v.begin() + (10 - N) == sent2);
|
||||
assert(std::as_const(v).begin() + (10 - N) == sent2);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple>();
|
||||
test<N, Tie>();
|
||||
test<N, GetFirst>();
|
||||
test<N, Multiply>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,206 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// template<bool OtherConst>
|
||||
// requires sentinel_for<inner-sentinel<Const>, inner-iterator<OtherConst>>
|
||||
// friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
|
||||
|
||||
#include <cassert>
|
||||
#include <compare>
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
#include "test_iterators.h"
|
||||
#include "test_range.h"
|
||||
|
||||
using Iterator = random_access_iterator<int*>;
|
||||
using ConstIterator = contiguous_iterator<const int*>;
|
||||
|
||||
template <bool Const>
|
||||
struct ComparableSentinel {
|
||||
using Iter = std::conditional_t<Const, ConstIterator, Iterator>;
|
||||
Iter iter_;
|
||||
|
||||
explicit ComparableSentinel() = default;
|
||||
constexpr explicit ComparableSentinel(const Iter& it) : iter_(it) {}
|
||||
|
||||
constexpr friend bool operator==(const Iterator& i, const ComparableSentinel& s) { return base(i) == base(s.iter_); }
|
||||
|
||||
constexpr friend bool operator==(const ConstIterator& i, const ComparableSentinel& s) {
|
||||
return base(i) == base(s.iter_);
|
||||
}
|
||||
};
|
||||
|
||||
struct ComparableView : IntBufferView {
|
||||
using IntBufferView::IntBufferView;
|
||||
|
||||
constexpr auto begin() { return Iterator(buffer_); }
|
||||
constexpr auto begin() const { return ConstIterator(buffer_); }
|
||||
constexpr auto end() { return ComparableSentinel<false>(Iterator(buffer_ + size_)); }
|
||||
constexpr auto end() const { return ComparableSentinel<true>(ConstIterator(buffer_ + size_)); }
|
||||
};
|
||||
|
||||
struct ConstIncompatibleView : IntBufferView {
|
||||
using IntBufferView::IntBufferView;
|
||||
|
||||
constexpr random_access_iterator<int*> begin() { return random_access_iterator<int*>(buffer_); }
|
||||
constexpr contiguous_iterator<const int*> begin() const { return contiguous_iterator<const int*>(buffer_); }
|
||||
constexpr sentinel_wrapper<random_access_iterator<int*>> end() {
|
||||
return sentinel_wrapper<random_access_iterator<int*>>(random_access_iterator<int*>(buffer_ + size_));
|
||||
}
|
||||
constexpr sentinel_wrapper<contiguous_iterator<const int*>> end() const {
|
||||
return sentinel_wrapper<contiguous_iterator<const int*>>(contiguous_iterator<const int*>(buffer_ + size_));
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr bool test() {
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
{
|
||||
// underlying simple-view: const and non-const have the same iterator/sentinel type
|
||||
using View = std::ranges::adjacent_transform_view<SimpleNonCommon, Fn, N>;
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
|
||||
// but adjacent_transform_view is never a simple-view
|
||||
static_assert(!simple_view<View>);
|
||||
|
||||
View v{SimpleNonCommon(buffer), Fn{}};
|
||||
|
||||
assert(v.begin() != v.end());
|
||||
assert(v.begin() + 1 != v.end());
|
||||
assert(v.begin() + 2 != v.end());
|
||||
assert(v.begin() + 3 != v.end());
|
||||
assert(v.begin() + (10 - N) == v.end());
|
||||
}
|
||||
|
||||
{
|
||||
// !simple-view: const and non-const have different iterator/sentinel types
|
||||
using View = std::ranges::adjacent_transform_view<NonSimpleNonCommon, Fn, N>;
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
static_assert(!simple_view<View>);
|
||||
|
||||
using Iter = std::ranges::iterator_t<View>;
|
||||
using ConstIter = std::ranges::iterator_t<const View>;
|
||||
static_assert(!std::is_same_v<Iter, ConstIter>);
|
||||
using Sentinel = std::ranges::sentinel_t<View>;
|
||||
using ConstSentinel = std::ranges::sentinel_t<const View>;
|
||||
static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
|
||||
|
||||
static_assert(weakly_equality_comparable_with<Iter, Sentinel>);
|
||||
static_assert(!weakly_equality_comparable_with<ConstIter, Sentinel>);
|
||||
static_assert(weakly_equality_comparable_with<Iter, ConstSentinel>);
|
||||
static_assert(weakly_equality_comparable_with<ConstIter, ConstSentinel>);
|
||||
|
||||
View v{NonSimpleNonCommon(buffer), Fn{}};
|
||||
|
||||
assert(v.begin() != v.end());
|
||||
assert(v.begin() + (10 - N) == v.end());
|
||||
|
||||
assert(v.begin() != std::as_const(v).end());
|
||||
assert(v.begin() + (10 - N) == std::as_const(v).end());
|
||||
// the above works because
|
||||
static_assert(std::convertible_to<Iter, ConstIter>);
|
||||
|
||||
assert(std::as_const(v).begin() != std::as_const(v).end());
|
||||
assert(std::as_const(v).begin() + (10 - N) == std::as_const(v).end());
|
||||
}
|
||||
|
||||
{
|
||||
// underlying const/non-const sentinel can be compared with both const/non-const iterator
|
||||
using View = std::ranges::adjacent_transform_view<ComparableView, Fn, N>;
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
static_assert(!simple_view<View>);
|
||||
|
||||
using Iter = std::ranges::iterator_t<View>;
|
||||
using ConstIter = std::ranges::iterator_t<const View>;
|
||||
static_assert(!std::is_same_v<Iter, ConstIter>);
|
||||
using Sentinel = std::ranges::sentinel_t<View>;
|
||||
using ConstSentinel = std::ranges::sentinel_t<const View>;
|
||||
static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
|
||||
|
||||
static_assert(weakly_equality_comparable_with<Iter, Sentinel>);
|
||||
static_assert(weakly_equality_comparable_with<ConstIter, Sentinel>);
|
||||
static_assert(weakly_equality_comparable_with<Iter, ConstSentinel>);
|
||||
static_assert(weakly_equality_comparable_with<ConstIter, ConstSentinel>);
|
||||
|
||||
View v{ComparableView(buffer), Fn{}};
|
||||
|
||||
assert(v.begin() != v.end());
|
||||
assert(v.begin() + (10 - N) == v.end());
|
||||
|
||||
static_assert(!std::convertible_to<Iter, ConstIter>);
|
||||
|
||||
assert(v.begin() != std::as_const(v).end());
|
||||
assert(v.begin() + (10 - N) == std::as_const(v).end());
|
||||
|
||||
assert(std::as_const(v).begin() != v.end());
|
||||
assert(std::as_const(v).begin() + (10 - N) == v.end());
|
||||
|
||||
assert(std::as_const(v).begin() != std::as_const(v).end());
|
||||
assert(std::as_const(v).begin() + (10 - N) == std::as_const(v).end());
|
||||
}
|
||||
|
||||
{
|
||||
// underlying const/non-const sentinel cannot be compared with non-const/const iterator
|
||||
|
||||
using View = std::ranges::adjacent_transform_view<ConstIncompatibleView, Fn, N>;
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
static_assert(!simple_view<View>);
|
||||
|
||||
using Iter = std::ranges::iterator_t<View>;
|
||||
using ConstIter = std::ranges::iterator_t<const View>;
|
||||
static_assert(!std::is_same_v<Iter, ConstIter>);
|
||||
using Sentinel = std::ranges::sentinel_t<View>;
|
||||
using ConstSentinel = std::ranges::sentinel_t<const View>;
|
||||
static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
|
||||
|
||||
static_assert(weakly_equality_comparable_with<Iter, Sentinel>);
|
||||
static_assert(!weakly_equality_comparable_with<ConstIter, Sentinel>);
|
||||
static_assert(!weakly_equality_comparable_with<Iter, ConstSentinel>);
|
||||
static_assert(weakly_equality_comparable_with<ConstIter, ConstSentinel>);
|
||||
|
||||
View v{ConstIncompatibleView{buffer}, Fn{}};
|
||||
|
||||
assert(v.begin() != v.end());
|
||||
assert(v.begin() + (10 - N) == v.end());
|
||||
|
||||
assert(std::as_const(v).begin() != std::as_const(v).end());
|
||||
assert(std::as_const(v).begin() + (10 - N) == std::as_const(v).end());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple>();
|
||||
test<N, Tie>();
|
||||
test<N, GetFirst>();
|
||||
test<N, Multiply>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,195 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// template<bool OtherConst>
|
||||
// requires sized_sentinel_for<inner-sentinel<Const>, inner-iterator<OtherConst>>
|
||||
// friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>>
|
||||
// operator-(const iterator<OtherConst>& x, const sentinel& y);
|
||||
|
||||
// template<bool OtherConst>
|
||||
// requires sized_sentinel_for<inner-sentinel<Const>, inner-iterator<OtherConst>>
|
||||
// friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>>
|
||||
// operator-(const sentinel& x, const iterator<OtherConst>& y);
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
|
||||
#include "../helpers.h"
|
||||
#include "../../range_adaptor_types.h"
|
||||
|
||||
// clang-format off
|
||||
template <class T, class U>
|
||||
concept HasMinus = std::invocable<std::minus<>,const T&, const U&>;
|
||||
|
||||
template <class T>
|
||||
concept SentinelHasMinus = HasMinus<std::ranges::sentinel_t<T>, std::ranges::iterator_t<T>>;
|
||||
// clang-format on
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test() {
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
{
|
||||
// underlying simple-view
|
||||
using View = std::ranges::adjacent_transform_view<ForwardSizedNonCommon, Fn, N>;
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
// but adjacent_transform_view is never a simple-view
|
||||
static_assert(!simple_view<View>);
|
||||
|
||||
View v{ForwardSizedNonCommon(buffer), Fn{}};
|
||||
|
||||
auto it = v.begin();
|
||||
auto st = v.end();
|
||||
assert(st - it == (10 - N));
|
||||
assert(st - std::ranges::next(it, 1) == (9 - N));
|
||||
|
||||
assert(it - st == (static_cast<int>(N) - 10));
|
||||
assert(std::ranges::next(it, 1) - st == (static_cast<int>(N) - 9));
|
||||
static_assert(SentinelHasMinus<View>);
|
||||
}
|
||||
|
||||
{
|
||||
// empty range
|
||||
using View = std::ranges::adjacent_transform_view<ForwardSizedNonCommon, Fn, N>;
|
||||
View v{ForwardSizedNonCommon(buffer, 0), Fn{}};
|
||||
|
||||
auto it = v.begin();
|
||||
auto st = v.end();
|
||||
assert(st - it == 0);
|
||||
assert(it - st == 0);
|
||||
}
|
||||
|
||||
{
|
||||
// N > size of underlying range
|
||||
using View = std::ranges::adjacent_transform_view<ForwardSizedNonCommon, Fn, 5>;
|
||||
View v{ForwardSizedNonCommon(buffer, 3), Fn{}};
|
||||
|
||||
auto it = v.begin();
|
||||
auto st = v.end();
|
||||
assert(st - it == 0);
|
||||
assert(it - st == 0);
|
||||
}
|
||||
|
||||
{
|
||||
// underlying sentinel does not model sized_sentinel_for
|
||||
using View = std::ranges::adjacent_transform_view<decltype(std::views::iota(0)), MakeTuple, N>;
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
static_assert(!SentinelHasMinus<View>);
|
||||
}
|
||||
|
||||
{
|
||||
// const incompatible:
|
||||
// underlying const sentinels cannot subtract underlying iterators
|
||||
// underlying sentinels cannot subtract underlying const iterators
|
||||
using View = std::ranges::adjacent_transform_view<NonSimpleForwardSizedNonCommon, Fn, N>;
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
static_assert(!simple_view<View>);
|
||||
|
||||
using Iter = std::ranges::iterator_t<View>;
|
||||
using ConstIter = std::ranges::iterator_t<const View>;
|
||||
static_assert(!std::is_same_v<Iter, ConstIter>);
|
||||
using Sentinel = std::ranges::sentinel_t<View>;
|
||||
using ConstSentinel = std::ranges::sentinel_t<const View>;
|
||||
static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
|
||||
|
||||
static_assert(HasMinus<Iter, Sentinel>);
|
||||
static_assert(HasMinus<Sentinel, Iter>);
|
||||
static_assert(HasMinus<ConstIter, ConstSentinel>);
|
||||
static_assert(HasMinus<ConstSentinel, ConstIter>);
|
||||
|
||||
View v{NonSimpleForwardSizedNonCommon{buffer}, Fn{}};
|
||||
|
||||
auto it = v.begin();
|
||||
auto const_it = std::as_const(v).begin();
|
||||
auto st = v.end();
|
||||
auto const_st = std::as_const(v).end();
|
||||
|
||||
int n = N;
|
||||
|
||||
assert(it - st == (n - 10));
|
||||
assert(st - it == (10 - n));
|
||||
assert(const_it - const_st == (n - 10));
|
||||
assert(const_st - const_it == (10 - n));
|
||||
|
||||
static_assert(!HasMinus<Iter, ConstSentinel>);
|
||||
static_assert(!HasMinus<ConstSentinel, Iter>);
|
||||
static_assert(!HasMinus<ConstIter, Sentinel>);
|
||||
static_assert(!HasMinus<Sentinel, ConstIter>);
|
||||
}
|
||||
|
||||
{
|
||||
// const compatible allow non-const to const conversion
|
||||
using View = std::ranges::adjacent_transform_view<ConstCompatibleForwardSized, Fn, N>;
|
||||
static_assert(!std::ranges::common_range<View>);
|
||||
static_assert(!simple_view<View>);
|
||||
|
||||
using Iter = std::ranges::iterator_t<View>;
|
||||
using ConstIter = std::ranges::iterator_t<const View>;
|
||||
static_assert(!std::is_same_v<Iter, ConstIter>);
|
||||
using Sentinel = std::ranges::sentinel_t<View>;
|
||||
using ConstSentinel = std::ranges::sentinel_t<const View>;
|
||||
static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
|
||||
|
||||
static_assert(HasMinus<Iter, Sentinel>);
|
||||
static_assert(HasMinus<Sentinel, Iter>);
|
||||
static_assert(HasMinus<ConstIter, ConstSentinel>);
|
||||
static_assert(HasMinus<ConstSentinel, ConstIter>);
|
||||
static_assert(HasMinus<Iter, ConstSentinel>);
|
||||
static_assert(HasMinus<ConstSentinel, Iter>);
|
||||
static_assert(HasMinus<ConstIter, Sentinel>);
|
||||
static_assert(HasMinus<Sentinel, ConstIter>);
|
||||
|
||||
View v{ConstCompatibleForwardSized{buffer}, Fn{}};
|
||||
|
||||
auto it = v.begin();
|
||||
auto const_it = std::as_const(v).begin();
|
||||
auto st = v.end();
|
||||
auto const_st = std::as_const(v).end();
|
||||
|
||||
int n = N;
|
||||
|
||||
assert(it - st == (n - 10));
|
||||
assert(st - it == (10 - n));
|
||||
assert(const_it - const_st == (n - 10));
|
||||
assert(const_st - const_it == (10 - n));
|
||||
assert(it - const_st == (n - 10));
|
||||
assert(const_st - it == (10 - n));
|
||||
assert(const_it - st == (n - 10));
|
||||
assert(st - const_it == (10 - n));
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple>();
|
||||
test<N, Tie>();
|
||||
test<N, GetFirst>();
|
||||
test<N, Multiply>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<4>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++20
|
||||
|
||||
// constexpr auto size() requires sized_range<InnerView>
|
||||
// constexpr auto size() const requires sized_range<const InnerView>
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "helpers.h"
|
||||
#include "../range_adaptor_types.h"
|
||||
|
||||
int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
struct View : std::ranges::view_base {
|
||||
std::size_t size_ = 0;
|
||||
constexpr View(std::size_t s) : size_(s) {}
|
||||
constexpr auto begin() const { return buffer; }
|
||||
constexpr auto end() const { return buffer + size_; }
|
||||
};
|
||||
|
||||
struct SizedNonConst : std::ranges::view_base {
|
||||
using iterator = forward_iterator<int*>;
|
||||
std::size_t size_ = 0;
|
||||
constexpr SizedNonConst(std::size_t s) : size_(s) {}
|
||||
constexpr auto begin() const { return iterator{buffer}; }
|
||||
constexpr auto end() const { return iterator{buffer + size_}; }
|
||||
constexpr std::size_t size() { return size_; }
|
||||
};
|
||||
|
||||
struct StrangeSizeView : std::ranges::view_base {
|
||||
constexpr auto begin() const { return buffer; }
|
||||
constexpr auto end() const { return buffer + 8; }
|
||||
|
||||
constexpr auto size() { return 5; }
|
||||
constexpr auto size() const { return 6; }
|
||||
};
|
||||
|
||||
// Test with different values of N for a sized view
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test_sized_view() {
|
||||
std::ranges::adjacent_transform_view<View, Fn, N> v(View(8), Fn{});
|
||||
static_assert(std::ranges::sized_range<decltype(v)>);
|
||||
static_assert(std::ranges::sized_range<const decltype(v)>);
|
||||
|
||||
auto expected_size = 8 - (N - 1);
|
||||
assert(v.size() == expected_size);
|
||||
assert(std::as_const(v).size() == expected_size);
|
||||
}
|
||||
|
||||
// Test with different values of N for a non-const sized view
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test_nonconst_sized() {
|
||||
std::ranges::adjacent_transform_view<SizedNonConst, Fn, N> v(SizedNonConst(5), Fn{});
|
||||
static_assert(std::ranges::sized_range<decltype(v)>);
|
||||
static_assert(!std::ranges::sized_range<const decltype(v)>);
|
||||
|
||||
auto expected_size = 5 - (N - 1);
|
||||
assert(v.size() == expected_size);
|
||||
}
|
||||
|
||||
// Test with different values of N for a view with different const/non-const sizes
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test_strange_size() {
|
||||
std::ranges::adjacent_transform_view<StrangeSizeView, Fn, N> v(StrangeSizeView{}, Fn{});
|
||||
static_assert(std::ranges::sized_range<decltype(v)>);
|
||||
static_assert(std::ranges::sized_range<const decltype(v)>);
|
||||
|
||||
assert(v.size() == 5 - (N - 1));
|
||||
assert(std::as_const(v).size() == 6 - (N - 1));
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test_empty_range() {
|
||||
std::ranges::adjacent_transform_view<View, Fn, N> v(View(0), Fn{});
|
||||
static_assert(std::ranges::sized_range<decltype(v)>);
|
||||
static_assert(std::ranges::sized_range<const decltype(v)>);
|
||||
|
||||
assert(v.size() == 0);
|
||||
assert(std::as_const(v).size() == 0);
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test_N_greater_than_size() {
|
||||
if constexpr (N > 2) {
|
||||
std::ranges::adjacent_transform_view<View, Fn, N> v(View(2), Fn{});
|
||||
static_assert(std::ranges::sized_range<decltype(v)>);
|
||||
static_assert(std::ranges::sized_range<const decltype(v)>);
|
||||
assert(v.size() == 0);
|
||||
assert(std::as_const(v).size() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N, class Fn>
|
||||
constexpr void test() {
|
||||
test_sized_view<N, Fn>();
|
||||
test_nonconst_sized<N, Fn>();
|
||||
test_strange_size<N, Fn>();
|
||||
test_empty_range<N, Fn>();
|
||||
test_N_greater_than_size<N, Fn>();
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr void test() {
|
||||
test<N, MakeTuple>();
|
||||
test<N, Tie>();
|
||||
test<N, GetFirst>();
|
||||
test<N, Multiply>();
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test<1>();
|
||||
test<2>();
|
||||
test<3>();
|
||||
test<5>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -57,6 +57,7 @@ constexpr bool test() {
|
||||
|
||||
#if TEST_STD_VER >= 23
|
||||
testOne<std::ranges::adjacent_view<View, 5>>();
|
||||
testOne<std::ranges::adjacent_transform_view<View, Pred, 5>>();
|
||||
testOne<std::ranges::chunk_by_view<View, Pred>>();
|
||||
testOne<std::ranges::repeat_view<Pred>>();
|
||||
testOne<std::ranges::zip_transform_view<Pred, View>>();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user