[libc++] Implement P1899 ranges::stride_view (#65200)
Implement `ranges::stride_view` in libc++. This PR was migrated from Phabricator (https://reviews.llvm.org/D156924). Closes #105198 Co-authored-by: Louis Dionne <ldionne.2@gmail.com> Co-authored-by: A. Jiang <de34@live.cn>
This commit is contained in:
@@ -390,6 +390,8 @@ Status
|
||||
---------------------------------------------------------- -----------------
|
||||
``__cpp_lib_ranges_starts_ends_with`` ``202106L``
|
||||
---------------------------------------------------------- -----------------
|
||||
``__cpp_lib_ranges_stride`` ``202207L``
|
||||
---------------------------------------------------------- -----------------
|
||||
``__cpp_lib_ranges_to_container`` ``202202L``
|
||||
---------------------------------------------------------- -----------------
|
||||
``__cpp_lib_ranges_zip`` ``202110L``
|
||||
|
||||
@@ -39,6 +39,7 @@ Implemented Papers
|
||||
------------------
|
||||
|
||||
- P2440R1: ``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right`` (`Github <https://llvm.org/PR105184>`__)
|
||||
- P1899R3: ``stride_view`` (`Github <https://llvm.org/PR105198>`__)
|
||||
- P3936R1: Safer ``atomic_ref::address`` (`Github <https://llvm.org/PR189594>`__)
|
||||
- P3953R3: Rename ``std::runtime_format`` (`Github <https://llvm.org/PR189624>`__)
|
||||
- P4052R0: Renaming saturation arithmetic functions (`Github <https://llvm.org/PR189589>`__)
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
"`P1223R5 <https://wg21.link/P1223R5>`__","``ranges::find_last()``, ``ranges::find_last_if()``, and ``ranges::find_last_if_not()``","2022-07 (Virtual)","|Complete|","19","`#105194 <https://github.com/llvm/llvm-project/issues/105194>`__",""
|
||||
"`P1467R9 <https://wg21.link/P1467R9>`__","Extended ``floating-point`` types and standard names","2022-07 (Virtual)","","","`#105196 <https://github.com/llvm/llvm-project/issues/105196>`__",""
|
||||
"`P1642R11 <https://wg21.link/P1642R11>`__","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","2022-07 (Virtual)","","","`#105197 <https://github.com/llvm/llvm-project/issues/105197>`__",""
|
||||
"`P1899R3 <https://wg21.link/P1899R3>`__","``stride_view``","2022-07 (Virtual)","","","`#105198 <https://github.com/llvm/llvm-project/issues/105198>`__",""
|
||||
"`P1899R3 <https://wg21.link/P1899R3>`__","``stride_view``","2022-07 (Virtual)","|Complete|","23","`#105198 <https://github.com/llvm/llvm-project/issues/105198>`__",""
|
||||
"`P2093R14 <https://wg21.link/P2093R14>`__","Formatted output","2022-07 (Virtual)","|Complete|","18","`#105199 <https://github.com/llvm/llvm-project/issues/105199>`__",""
|
||||
"`P2165R4 <https://wg21.link/P2165R4>`__","Compatibility between ``tuple``, ``pair`` and ``tuple-like`` objects","2022-07 (Virtual)","|Partial|","","`#105200 <https://github.com/llvm/llvm-project/issues/105200>`__","Only the part for ``zip_view`` is implemented."
|
||||
"`P2278R4 <https://wg21.link/P2278R4>`__","``cbegin`` should always return a constant iterator","2022-07 (Virtual)","","","`#105201 <https://github.com/llvm/llvm-project/issues/105201>`__",""
|
||||
|
||||
|
@@ -751,6 +751,7 @@ set(files
|
||||
__ranges/single_view.h
|
||||
__ranges/size.h
|
||||
__ranges/split_view.h
|
||||
__ranges/stride_view.h
|
||||
__ranges/subrange.h
|
||||
__ranges/take_view.h
|
||||
__ranges/take_while_view.h
|
||||
|
||||
410
libcxx/include/__ranges/stride_view.h
Normal file
410
libcxx/include/__ranges/stride_view.h
Normal file
@@ -0,0 +1,410 @@
|
||||
// -*- 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_STRIDE_VIEW_H
|
||||
#define _LIBCPP___RANGES_STRIDE_VIEW_H
|
||||
|
||||
#include <__assert>
|
||||
#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 <__config>
|
||||
#include <__functional/bind_back.h>
|
||||
#include <__iterator/advance.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/default_sentinel.h>
|
||||
#include <__iterator/distance.h>
|
||||
#include <__iterator/iter_move.h>
|
||||
#include <__iterator/iter_swap.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/all.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/enable_borrowed_range.h>
|
||||
#include <__ranges/range_adaptor.h>
|
||||
#include <__ranges/view_interface.h>
|
||||
#include <__type_traits/make_unsigned.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 _Value>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _Value __div_ceil(_Value __left, _Value __right) {
|
||||
_Value __r = __left / __right;
|
||||
if (__left % __right) {
|
||||
++__r;
|
||||
}
|
||||
return __r;
|
||||
}
|
||||
|
||||
template <input_range _View>
|
||||
requires view<_View>
|
||||
class stride_view : public view_interface<stride_view<_View>> {
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
|
||||
range_difference_t<_View> __stride_ = 0;
|
||||
|
||||
template <bool _Const>
|
||||
class __iterator;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit stride_view(_View __base, range_difference_t<_View> __stride)
|
||||
: __base_(std::move(__base)), __stride_(__stride) {
|
||||
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__stride > 0, "The value of stride must be greater than 0");
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
|
||||
requires copy_constructible<_View>
|
||||
{
|
||||
return __base_;
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr range_difference_t<_View> stride() const noexcept { return __stride_; }
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
|
||||
requires(!__simple_view<_View>)
|
||||
{
|
||||
return __iterator</*_Const=*/false>(this, ranges::begin(__base_), 0);
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
|
||||
requires range<const _View>
|
||||
{
|
||||
return __iterator</*_Const=*/true>(this, ranges::begin(__base_), 0);
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end()
|
||||
requires(!__simple_view<_View>)
|
||||
{
|
||||
if constexpr (common_range<_View> && sized_range<_View> && forward_range<_View>) {
|
||||
auto __missing = (__stride_ - ranges::distance(__base_) % __stride_) % __stride_;
|
||||
return __iterator</*_Const=*/false>(this, ranges::end(__base_), __missing);
|
||||
} else if constexpr (common_range<_View> && !bidirectional_range<_View>) {
|
||||
return __iterator</*_Const=*/false>(this, ranges::end(__base_), 0);
|
||||
} else {
|
||||
return default_sentinel;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
|
||||
requires(range<const _View>)
|
||||
{
|
||||
if constexpr (common_range<const _View> && sized_range<const _View> && forward_range<const _View>) {
|
||||
auto __missing = (__stride_ - ranges::distance(__base_) % __stride_) % __stride_;
|
||||
return __iterator</*_Const=*/true>(this, ranges::end(__base_), __missing);
|
||||
} else if constexpr (common_range<const _View> && !bidirectional_range<const _View>) {
|
||||
return __iterator</*_Const=*/true>(this, ranges::end(__base_), 0);
|
||||
} else {
|
||||
return default_sentinel;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
|
||||
requires sized_range<_View>
|
||||
{
|
||||
return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_));
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
|
||||
requires sized_range<const _View>
|
||||
{
|
||||
return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_));
|
||||
}
|
||||
}; // class stride_view
|
||||
|
||||
template <class _Range>
|
||||
stride_view(_Range&&, range_difference_t<_Range>) -> stride_view<views::all_t<_Range>>;
|
||||
|
||||
template <class _View>
|
||||
struct __stride_iterator_category {};
|
||||
|
||||
template <forward_range _View>
|
||||
struct __stride_iterator_category<_View> {
|
||||
using _Cat _LIBCPP_NODEBUG = typename iterator_traits<iterator_t<_View>>::iterator_category;
|
||||
using iterator_category =
|
||||
_If<derived_from<_Cat, random_access_iterator_tag>,
|
||||
/* then */ random_access_iterator_tag,
|
||||
/* else */ _Cat >;
|
||||
};
|
||||
|
||||
template <input_range _View>
|
||||
requires view<_View>
|
||||
template <bool _Const>
|
||||
class stride_view<_View>::__iterator : public __stride_iterator_category<__maybe_const<_Const, _View>> {
|
||||
using _Parent _LIBCPP_NODEBUG = __maybe_const<_Const, stride_view<_View>>;
|
||||
using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>;
|
||||
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_Base> __current_ = iterator_t<_Base>();
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS ranges::sentinel_t<_Base> __end_ = ranges::sentinel_t<_Base>();
|
||||
range_difference_t<_Base> __stride_ = 0;
|
||||
range_difference_t<_Base> __missing_ = 0;
|
||||
|
||||
friend stride_view;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(
|
||||
_Parent* __parent, ranges::iterator_t<_Base> __current, range_difference_t<_Base> __missing)
|
||||
: __current_(std::move(__current)),
|
||||
__end_(ranges::end(__parent->__base_)),
|
||||
__stride_(__parent->__stride_),
|
||||
__missing_(__missing) {}
|
||||
|
||||
static consteval auto __get_stride_view_iterator_concept() {
|
||||
if constexpr (random_access_range<_Base>) {
|
||||
return random_access_iterator_tag{};
|
||||
} else if constexpr (bidirectional_range<_Base>) {
|
||||
return bidirectional_iterator_tag{};
|
||||
} else if constexpr (forward_range<_Base>) {
|
||||
return forward_iterator_tag{};
|
||||
} else {
|
||||
return input_iterator_tag{};
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
using difference_type = range_difference_t<_Base>;
|
||||
using value_type = range_value_t<_Base>;
|
||||
using iterator_concept = decltype(__get_stride_view_iterator_concept());
|
||||
// using iterator_category = inherited;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __iterator()
|
||||
requires default_initializable<iterator_t<_Base>>
|
||||
= default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
|
||||
requires _Const && convertible_to<ranges::iterator_t<_View>, iterator_t<_Base>> &&
|
||||
convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
|
||||
: __current_(std::move(__i.__current_)),
|
||||
__end_(std::move(__i.__end_)),
|
||||
__stride_(__i.__stride_),
|
||||
__missing_(__i.__missing_) {}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> const& base() const& noexcept { return __current_; }
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() && { return std::move(__current_); }
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const {
|
||||
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__current_ != __end_, "Cannot dereference an iterator at the end.");
|
||||
return *__current_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
|
||||
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__current_ != __end_, "Cannot increment an iterator already at the end.");
|
||||
__missing_ = ranges::advance(__current_, __stride_, __end_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) {
|
||||
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__current_ != __end_, "Cannot increment an iterator already at the end.");
|
||||
++*this;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
|
||||
requires forward_range<_Base>
|
||||
{
|
||||
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__current_ != __end_, "Cannot increment an iterator already at the end.");
|
||||
auto __tmp = *this;
|
||||
++*this;
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
|
||||
requires bidirectional_range<_Base>
|
||||
{
|
||||
ranges::advance(__current_, __missing_ - __stride_);
|
||||
__missing_ = 0;
|
||||
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 __n)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
if (__n > 0) {
|
||||
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(ranges::distance(__current_, __end_) > __stride_ * (__n - 1),
|
||||
"Advancing the iterator beyond the end is not allowed.");
|
||||
ranges::advance(__current_, __stride_ * (__n - 1));
|
||||
__missing_ = ranges::advance(__current_, __stride_, __end_);
|
||||
|
||||
} else if (__n < 0) {
|
||||
ranges::advance(__current_, __stride_ * __n + __missing_);
|
||||
__missing_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return *this += -__n;
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return *(*this + __n);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(__iterator const& __x, default_sentinel_t) {
|
||||
return __x.__current_ == __x.__end_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(__iterator const& __x, __iterator const& __y)
|
||||
requires equality_comparable<iterator_t<_Base>>
|
||||
{
|
||||
return __x.__current_ == __y.__current_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(__iterator const& __x, __iterator const& __y)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return __x.__current_ < __y.__current_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(__iterator const& __x, __iterator const& __y)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return __y < __x;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(__iterator const& __x, __iterator const& __y)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return !(__y < __x);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(__iterator const& __x, __iterator const& __y)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
return !(__x < __y);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(__iterator const& __x, __iterator const& __y)
|
||||
requires random_access_range<_Base> && three_way_comparable<iterator_t<_Base>>
|
||||
{
|
||||
return __x.__current_ <=> __y.__current_;
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(__iterator const& __i, difference_type __s)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
auto __r = __i;
|
||||
__r += __s;
|
||||
return __r;
|
||||
}
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __s, __iterator const& __i)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
auto __r = __i;
|
||||
__r += __s;
|
||||
return __r;
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator const& __i, difference_type __s)
|
||||
requires random_access_range<_Base>
|
||||
{
|
||||
auto __r = __i;
|
||||
__r -= __s;
|
||||
return __r;
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
|
||||
operator-(__iterator const& __x, __iterator const& __y)
|
||||
requires sized_sentinel_for<iterator_t<_Base>, iterator_t<_Base>>
|
||||
{
|
||||
if constexpr (forward_range<_Base>) {
|
||||
auto __n = __x.__current_ - __y.__current_;
|
||||
return (__n + __x.__missing_ - __y.__missing_) / __x.__stride_;
|
||||
}
|
||||
auto __n = __x.__current_ - __y.__current_;
|
||||
if (__n < 0) {
|
||||
return -ranges::__div_ceil(-__n, __x.__stride_);
|
||||
}
|
||||
return ranges::__div_ceil(__n, __x.__stride_);
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
|
||||
operator-(default_sentinel_t, __iterator const& __x)
|
||||
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
|
||||
{
|
||||
return ranges::__div_ceil(__x.__end_ - __x.__current_, __x.__stride_);
|
||||
}
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
|
||||
operator-(__iterator const& __x, default_sentinel_t __y)
|
||||
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
|
||||
{
|
||||
return -(__y - __x);
|
||||
}
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_rvalue_reference_t<_Base>
|
||||
iter_move(__iterator const& __it) noexcept(noexcept(ranges::iter_move(__it.__current_))) {
|
||||
return ranges::iter_move(__it.__current_);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI friend constexpr void
|
||||
iter_swap(__iterator const& __x,
|
||||
__iterator const& __y) noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_)))
|
||||
requires indirectly_swappable<iterator_t<_Base>>
|
||||
{
|
||||
return ranges::iter_swap(__x.__current_, __y.__current_);
|
||||
}
|
||||
}; // class stride_view::__iterator
|
||||
|
||||
template <class _Tp>
|
||||
inline constexpr bool enable_borrowed_range<stride_view<_Tp>> = enable_borrowed_range<_Tp>;
|
||||
|
||||
namespace views {
|
||||
namespace __stride_view {
|
||||
struct __fn {
|
||||
// clang-format off
|
||||
template <viewable_range _Range>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI
|
||||
constexpr auto operator()(_Range&& __range, range_difference_t<_Range> __n) const
|
||||
noexcept(noexcept(stride_view{std::forward<_Range>(__range), __n}))
|
||||
-> decltype( stride_view{std::forward<_Range>(__range), __n})
|
||||
{ return stride_view(std::forward<_Range>(__range), __n); }
|
||||
// clang-format on
|
||||
|
||||
template <class _Np>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Np&& __n) const {
|
||||
return __pipeable(std::__bind_back(*this, std::forward<_Np>(__n)));
|
||||
}
|
||||
};
|
||||
} // namespace __stride_view
|
||||
|
||||
inline namespace __cpo {
|
||||
inline constexpr auto stride = __stride_view::__fn{};
|
||||
} // namespace __cpo
|
||||
} // namespace views
|
||||
|
||||
} // namespace ranges
|
||||
|
||||
#endif // _LIBCPP_STD_VER >= 23
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // _LIBCPP___RANGES_STRIDE_VIEW_H
|
||||
@@ -1942,6 +1942,10 @@ module std [system] {
|
||||
header "__ranges/split_view.h"
|
||||
export std.functional.bind_back
|
||||
}
|
||||
module stride_view {
|
||||
header "__ranges/stride_view.h"
|
||||
export std.functional.bind_back
|
||||
}
|
||||
module subrange {
|
||||
header "__ranges/subrange.h"
|
||||
export std.ranges.subrange_fwd
|
||||
|
||||
@@ -407,6 +407,17 @@ namespace std::ranges {
|
||||
class chunk_by_view; // C++23
|
||||
|
||||
namespace views { inline constexpr unspecified chunk_by = unspecified; } // C++23
|
||||
|
||||
// [range.stride.view], stride view
|
||||
template<input_range V>
|
||||
requires view<V>
|
||||
class stride_view; // C++23
|
||||
|
||||
template<class V>
|
||||
constexpr bool enable_borrowed_range<stride_view<V>> =
|
||||
enable_borrowed_range<V>; // C++23
|
||||
|
||||
namespace views { inline constexpr unspecified stride = unspecified; } // C++23
|
||||
}
|
||||
|
||||
namespace std {
|
||||
@@ -497,6 +508,7 @@ namespace std {
|
||||
# include <__ranges/from_range.h>
|
||||
# include <__ranges/join_with_view.h>
|
||||
# include <__ranges/repeat_view.h>
|
||||
# include <__ranges/stride_view.h>
|
||||
# include <__ranges/to.h>
|
||||
# include <__ranges/zip_transform_view.h>
|
||||
# include <__ranges/zip_view.h>
|
||||
|
||||
@@ -218,6 +218,7 @@ __cpp_lib_ranges_join_with 202202L <ranges>
|
||||
__cpp_lib_ranges_repeat 202207L <ranges>
|
||||
__cpp_lib_ranges_slide 202202L <ranges>
|
||||
__cpp_lib_ranges_starts_ends_with 202106L <algorithm>
|
||||
__cpp_lib_ranges_stride 202207L <ranges>
|
||||
__cpp_lib_ranges_to_container 202202L <ranges>
|
||||
__cpp_lib_ranges_zip 202110L <ranges> <tuple> <utility>
|
||||
__cpp_lib_ratio 202306L <ratio>
|
||||
@@ -534,6 +535,7 @@ __cpp_lib_void_t 201411L <type_traits>
|
||||
# define __cpp_lib_ranges_repeat 202207L
|
||||
// # define __cpp_lib_ranges_slide 202202L
|
||||
# define __cpp_lib_ranges_starts_ends_with 202106L
|
||||
# define __cpp_lib_ranges_stride 202207L
|
||||
# define __cpp_lib_ranges_to_container 202202L
|
||||
# define __cpp_lib_ranges_zip 202110L
|
||||
// # define __cpp_lib_reference_from_temporary 202202L
|
||||
|
||||
@@ -341,7 +341,6 @@ export namespace std {
|
||||
using std::ranges::views::chunk_by;
|
||||
}
|
||||
|
||||
# if 0
|
||||
// [range.stride], stride view
|
||||
using std::ranges::stride_view;
|
||||
|
||||
@@ -349,6 +348,7 @@ export namespace std {
|
||||
using std::ranges::views::stride;
|
||||
}
|
||||
|
||||
# if 0
|
||||
using std::ranges::cartesian_product_view;
|
||||
|
||||
namespace views {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
|
||||
// XFAIL:libcpp-hardening-mode=debug && availability-verbose_abort-missing
|
||||
|
||||
// constexpr explicit stride_view(_View, range_difference_t<_View>)
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "check_assertion.h"
|
||||
|
||||
int main(int, char**) {
|
||||
int range[] = {1, 2, 3};
|
||||
TEST_LIBCPP_ASSERT_FAILURE(
|
||||
[&range] { std::ranges::stride_view sv(range, 0); }(), "The value of stride must be greater than 0");
|
||||
TEST_LIBCPP_ASSERT_FAILURE(
|
||||
[&range] { std::ranges::stride_view sv(range, -1); }(), "The value of stride must be greater than 0");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// REQUIRES: libcpp-hardening-mode={{fast|extensive|debug}}
|
||||
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
|
||||
|
||||
// constexpr decltype(auto) operator*() const
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "check_assertion.h"
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
int range[] = {1, 2, 3};
|
||||
auto view = std::ranges::views::stride(range, 3);
|
||||
auto it = view.begin();
|
||||
++it;
|
||||
TEST_LIBCPP_ASSERT_FAILURE(*std::as_const(it), "Cannot dereference an iterator at the end.");
|
||||
}
|
||||
{
|
||||
int range[] = {1, 2, 3};
|
||||
auto view = std::ranges::views::stride(range, 4);
|
||||
auto it = view.begin();
|
||||
++it;
|
||||
TEST_LIBCPP_ASSERT_FAILURE(*std::as_const(it), "Cannot dereference an iterator at the end.");
|
||||
}
|
||||
{
|
||||
int range[] = {1, 2, 3};
|
||||
auto view = std::ranges::views::stride(range, 4);
|
||||
auto it = view.end();
|
||||
TEST_LIBCPP_ASSERT_FAILURE(*std::as_const(it), "Cannot dereference an iterator at the end.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
// REQUIRES: libcpp-hardening-mode={{fast|extensive|debug}}
|
||||
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
|
||||
|
||||
// constexpr __iterator& operator++()
|
||||
// constexpr void operator++(int)
|
||||
// constexpr __iterator operator++(int)
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "check_assertion.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
template <class Iter, class Sent = sentinel_wrapper<Iter>>
|
||||
struct MinimalView : std::ranges::view_base {
|
||||
Iter begin_;
|
||||
Sent end_;
|
||||
|
||||
constexpr MinimalView(Iter b, Sent e) : begin_(b), end_(e) {}
|
||||
MinimalView(MinimalView&&) = default;
|
||||
MinimalView& operator=(MinimalView&&) = default;
|
||||
|
||||
constexpr Iter begin() const { return begin_; }
|
||||
constexpr Sent end() const { return end_; }
|
||||
};
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
int range[] = {1, 2, 3};
|
||||
using View = MinimalView<cpp17_input_iterator<int*>>;
|
||||
auto view = std::ranges::views::stride(
|
||||
View(cpp17_input_iterator(range), sentinel_wrapper(cpp17_input_iterator(range + 3))), 3);
|
||||
auto it = view.begin();
|
||||
++it;
|
||||
TEST_LIBCPP_ASSERT_FAILURE(it++, "Cannot increment an iterator already at the end.");
|
||||
TEST_LIBCPP_ASSERT_FAILURE(++it, "Cannot increment an iterator already at the end.");
|
||||
}
|
||||
{
|
||||
int range[] = {1, 2, 3};
|
||||
using View = MinimalView<forward_iterator<int*>, forward_iterator<int*>>;
|
||||
auto view = std::ranges::views::stride(View(forward_iterator(range), forward_iterator(range + 3)), 3);
|
||||
auto it = view.begin();
|
||||
++it;
|
||||
TEST_LIBCPP_ASSERT_FAILURE(it++, "Cannot increment an iterator already at the end.");
|
||||
TEST_LIBCPP_ASSERT_FAILURE(++it, "Cannot increment an iterator already at the end.");
|
||||
}
|
||||
{
|
||||
int range[] = {1, 2, 3};
|
||||
using View = MinimalView<forward_iterator<int*>, forward_iterator<int*>>;
|
||||
auto view = std::ranges::views::stride(View(forward_iterator(range), forward_iterator(range + 3)), 3);
|
||||
auto it = view.end();
|
||||
TEST_LIBCPP_ASSERT_FAILURE(it++, "Cannot increment an iterator already at the end.");
|
||||
TEST_LIBCPP_ASSERT_FAILURE(++it, "Cannot increment an iterator already at the end.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 that stride_view's iterator member functions are properly marked nodiscard.
|
||||
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
void test() {
|
||||
int range[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
auto sv = std::ranges::stride_view(std::ranges::ref_view(range), 3);
|
||||
auto it = sv.begin();
|
||||
auto it2 = sv.begin();
|
||||
++it2;
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
it.base();
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::move(it).base();
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
*std::as_const(it);
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
it[0];
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
it + 1;
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
1 + it;
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
it2 - 1;
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
it2 - it;
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::default_sentinel_t() - it;
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
it - std::default_sentinel_t();
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::ranges::iter_move(it);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// REQUIRES: libcpp-hardening-mode={{fast|extensive|debug}}
|
||||
// XFAIL:libcpp-hardening-mode=debug && availability-verbose_abort-missing
|
||||
|
||||
// constexpr __iterator& operator+=(difference_type __n)
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "check_assertion.h"
|
||||
|
||||
int main(int, char**) {
|
||||
int range[] = {1, 2, 3};
|
||||
auto view = std::ranges::views::stride(range, 2);
|
||||
auto it = view.begin();
|
||||
TEST_LIBCPP_ASSERT_FAILURE(it += 3, "Advancing the iterator beyond the end is not allowed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 that stride_view's member functions are properly marked nodiscard.
|
||||
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
void test() {
|
||||
int range[] = {1, 2, 3};
|
||||
auto sv = std::ranges::stride_view(range, 2);
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
sv.base();
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::move(sv).base();
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
sv.begin();
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
sv.end();
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
sv.size();
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
sv.stride();
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::views::stride(range, 2);
|
||||
}
|
||||
@@ -68,6 +68,10 @@
|
||||
# error "__cpp_lib_ranges_slide should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_stride
|
||||
# error "__cpp_lib_ranges_stride should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined before c++23"
|
||||
# endif
|
||||
@@ -126,6 +130,10 @@
|
||||
# error "__cpp_lib_ranges_slide should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_stride
|
||||
# error "__cpp_lib_ranges_stride should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined before c++23"
|
||||
# endif
|
||||
@@ -184,6 +192,10 @@
|
||||
# error "__cpp_lib_ranges_slide should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_stride
|
||||
# error "__cpp_lib_ranges_stride should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined before c++23"
|
||||
# endif
|
||||
@@ -245,6 +257,10 @@
|
||||
# error "__cpp_lib_ranges_slide should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_stride
|
||||
# error "__cpp_lib_ranges_stride should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined before c++23"
|
||||
# endif
|
||||
@@ -348,6 +364,13 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_ranges_stride
|
||||
# error "__cpp_lib_ranges_stride should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_stride != 202207L
|
||||
# error "__cpp_lib_ranges_stride should have the value 202207L in c++23"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
@@ -478,6 +501,13 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_ranges_stride
|
||||
# error "__cpp_lib_ranges_stride should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_stride != 202207L
|
||||
# error "__cpp_lib_ranges_stride should have the value 202207L in c++26"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
|
||||
@@ -704,6 +704,10 @@
|
||||
# error "__cpp_lib_ranges_starts_ends_with should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_stride
|
||||
# error "__cpp_lib_ranges_stride should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined before c++23"
|
||||
# endif
|
||||
@@ -1668,6 +1672,10 @@
|
||||
# error "__cpp_lib_ranges_starts_ends_with should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_stride
|
||||
# error "__cpp_lib_ranges_stride should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined before c++23"
|
||||
# endif
|
||||
@@ -2797,6 +2805,10 @@
|
||||
# error "__cpp_lib_ranges_starts_ends_with should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_stride
|
||||
# error "__cpp_lib_ranges_stride should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined before c++23"
|
||||
# endif
|
||||
@@ -4193,6 +4205,10 @@
|
||||
# error "__cpp_lib_ranges_starts_ends_with should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_stride
|
||||
# error "__cpp_lib_ranges_stride should not be defined before c++23"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should not be defined before c++23"
|
||||
# endif
|
||||
@@ -5808,6 +5824,13 @@
|
||||
# error "__cpp_lib_ranges_starts_ends_with should have the value 202106L in c++23"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_ranges_stride
|
||||
# error "__cpp_lib_ranges_stride should be defined in c++23"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_stride != 202207L
|
||||
# error "__cpp_lib_ranges_stride should have the value 202207L in c++23"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++23"
|
||||
# endif
|
||||
@@ -7747,6 +7770,13 @@
|
||||
# error "__cpp_lib_ranges_starts_ends_with should have the value 202106L in c++26"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_ranges_stride
|
||||
# error "__cpp_lib_ranges_stride should be defined in c++26"
|
||||
# endif
|
||||
# if __cpp_lib_ranges_stride != 202207L
|
||||
# error "__cpp_lib_ranges_stride should have the value 202207L in c++26"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_ranges_to_container
|
||||
# error "__cpp_lib_ranges_to_container should be defined in c++26"
|
||||
# endif
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
|
||||
// std::views::stride
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "types.h"
|
||||
|
||||
constexpr BasicTestView<cpp17_input_iterator<int*>> make_input_view(int* begin, int* end) {
|
||||
return BasicTestView<cpp17_input_iterator<int*>>(cpp17_input_iterator<int*>(begin), cpp17_input_iterator<int*>(end));
|
||||
}
|
||||
|
||||
using ForwardStrideView = std::ranges::stride_view<BasicTestView<forward_iterator<int*>>>;
|
||||
using BidirStrideView = std::ranges::stride_view<BasicTestView<bidirectional_iterator<int*>>>;
|
||||
using RandomAccessStrideView = std::ranges::stride_view<BasicTestView<random_access_iterator<int*>>>;
|
||||
|
||||
using SizedForwardStrideView =
|
||||
std::ranges::stride_view<BasicTestView<random_access_iterator<int*>, random_access_iterator<int*>>>;
|
||||
using SizedInputStrideView = std::ranges::stride_view<BasicTestView<SizedInputIter, SizedInputIter>>;
|
||||
|
||||
static_assert(std::ranges::forward_range<ForwardStrideView>);
|
||||
static_assert(std::ranges::bidirectional_range<BidirStrideView>);
|
||||
static_assert(std::ranges::random_access_range<RandomAccessStrideView>);
|
||||
static_assert(std::ranges::forward_range<SizedForwardStrideView>);
|
||||
static_assert(std::sized_sentinel_for<std::ranges::iterator_t<SizedForwardStrideView>,
|
||||
std::ranges::iterator_t<SizedForwardStrideView>>);
|
||||
static_assert(std::sized_sentinel_for<std::ranges::iterator_t<SizedInputStrideView>,
|
||||
std::ranges::iterator_t<SizedInputStrideView>>);
|
||||
|
||||
constexpr bool test() {
|
||||
constexpr int N = 3;
|
||||
int arr[N] = {1, 2, 3};
|
||||
|
||||
// Test that `std::views::stride` is a range adaptor.
|
||||
// Check various forms of
|
||||
|
||||
// Test `view | views::stride`
|
||||
{
|
||||
using View = std::ranges::stride_view<BasicTestView<cpp17_input_iterator<int*>>>;
|
||||
auto view = make_input_view(arr, arr + N);
|
||||
std::same_as<View> decltype(auto) result = view | std::views::stride(2);
|
||||
auto it = result.begin();
|
||||
|
||||
assert(*it == arr[0]);
|
||||
std::ranges::advance(it, 1);
|
||||
assert(*it == arr[2]);
|
||||
}
|
||||
|
||||
// Test `adaptor | views::stride`
|
||||
auto twice = [](int i) { return i * 2; };
|
||||
{
|
||||
using View = std::ranges::stride_view<
|
||||
std::ranges::transform_view<BasicTestView<cpp17_input_iterator<int*>>, decltype(twice)>>;
|
||||
auto view = make_input_view(arr, arr + N);
|
||||
const auto partial = std::views::transform(twice) | std::views::stride(2);
|
||||
|
||||
std::same_as<View> decltype(auto) result = partial(view);
|
||||
auto it = result.begin();
|
||||
|
||||
assert(*it == twice(arr[0]));
|
||||
std::ranges::advance(it, 1);
|
||||
assert(*it == twice(arr[2]));
|
||||
}
|
||||
|
||||
// Test `views::stride | adaptor`
|
||||
{
|
||||
using View = std::ranges::transform_view< std::ranges::stride_view<BasicTestView<cpp17_input_iterator<int*>>>,
|
||||
decltype(twice)>;
|
||||
auto view = make_input_view(arr, arr + N);
|
||||
std::same_as<View> decltype(auto) result = std::views::stride(view, 2) | std::views::transform(twice);
|
||||
|
||||
auto it = result.begin();
|
||||
|
||||
assert(*it == twice(arr[0]));
|
||||
std::ranges::advance(it, 1);
|
||||
assert(*it == twice(arr[2]));
|
||||
}
|
||||
|
||||
// Check SFINAE friendliness
|
||||
{
|
||||
struct NotAViewableRange {};
|
||||
using View = BasicTestView<bidirectional_iterator<int*>>;
|
||||
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::stride)>);
|
||||
static_assert(!std::is_invocable_v<decltype(std::views::stride), NotAViewableRange, int>);
|
||||
|
||||
static_assert(CanBePiped<View, decltype(std::views::stride(5))>);
|
||||
static_assert(CanBePiped<View&, decltype(std::views::stride(5))>);
|
||||
static_assert(!CanBePiped<NotAViewableRange, decltype(std::views::stride(5))>);
|
||||
static_assert(!CanBePiped<View&, decltype(std::views::stride(NotAViewableRange{}))>);
|
||||
}
|
||||
|
||||
// A final sanity check.
|
||||
{
|
||||
static_assert(std::same_as<decltype(std::views::stride), decltype(std::ranges::views::stride)>);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
// constexpr V base() const& requires copy_constructible<V>;
|
||||
// constexpr V base() &&;
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "types.h"
|
||||
|
||||
template <typename T>
|
||||
constexpr bool has_lvalue_qualified_base(T&& t) {
|
||||
// Thanks to forwarding references, t's type is
|
||||
// preserved from the caller. No matter the type of
|
||||
// the argument, when it is used here, t is an l value
|
||||
// (after all, it has a name). Therefore, this code
|
||||
// will test whether the l value const-ref-qualified
|
||||
// version of base is callable.
|
||||
return requires { t.base(); };
|
||||
}
|
||||
|
||||
using CopyableInputView = CopyableView<cpp17_input_iterator<int*>>;
|
||||
using MoveOnlyInputView = MoveOnlyView<cpp17_input_iterator<int*>>;
|
||||
|
||||
constexpr bool test() {
|
||||
int buff[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
constexpr int N = 8;
|
||||
|
||||
// l-value ref qualified
|
||||
// const &
|
||||
{
|
||||
const std::ranges::stride_view<CopyableInputView> view(
|
||||
CopyableInputView(cpp17_input_iterator<int*>(buff), cpp17_input_iterator<int*>(buff + N)), 1);
|
||||
|
||||
static_assert(has_lvalue_qualified_base(view));
|
||||
|
||||
std::same_as<CopyableInputView> decltype(auto) s = view.base();
|
||||
assert(*s.begin() == *buff);
|
||||
}
|
||||
|
||||
// &
|
||||
{
|
||||
std::ranges::stride_view<CopyableInputView> view(
|
||||
CopyableInputView(cpp17_input_iterator<int*>(buff), cpp17_input_iterator<int*>(buff + N)), 1);
|
||||
|
||||
std::same_as<CopyableInputView> decltype(auto) s = view.base();
|
||||
assert(*s.begin() == *buff);
|
||||
|
||||
static_assert(has_lvalue_qualified_base(view));
|
||||
}
|
||||
|
||||
// r-value ref qualified
|
||||
// &&
|
||||
{
|
||||
std::ranges::stride_view<CopyableInputView> view(
|
||||
CopyableInputView(cpp17_input_iterator<int*>(buff), cpp17_input_iterator<int*>(buff + N)), 1);
|
||||
|
||||
static_assert(has_lvalue_qualified_base(view));
|
||||
|
||||
std::same_as<CopyableInputView> decltype(auto) s = std::move(view).base();
|
||||
assert(*s.begin() == *buff);
|
||||
}
|
||||
|
||||
// const &&
|
||||
{
|
||||
const std::ranges::stride_view<CopyableInputView> view(
|
||||
CopyableInputView(cpp17_input_iterator<int*>(buff), cpp17_input_iterator<int*>(buff + N)), 1);
|
||||
|
||||
static_assert(has_lvalue_qualified_base(view));
|
||||
|
||||
std::same_as<CopyableInputView> decltype(auto) s = std::move(view).base();
|
||||
assert(*s.begin() == *buff);
|
||||
}
|
||||
|
||||
// &&
|
||||
{
|
||||
std::ranges::stride_view<MoveOnlyInputView> view(
|
||||
MoveOnlyInputView(cpp17_input_iterator<int*>(buff), cpp17_input_iterator<int*>(buff + N)), 1);
|
||||
|
||||
// Because the base of the stride view is move only,
|
||||
// the const & version is not applicable and, therefore,
|
||||
// there is no l-value qualified base method.
|
||||
static_assert(!has_lvalue_qualified_base(view));
|
||||
|
||||
std::same_as<MoveOnlyInputView> decltype(auto) s = std::move(view).base();
|
||||
assert(*s.begin() == *buff);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// constexpr auto begin() requires(!simple-view<V>)
|
||||
// constexpr auto begin() const requires range<const V>
|
||||
|
||||
// Note: Checks here are augmented by checks in
|
||||
// iterator/ctor.copy.pass.cpp.
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
template <class T>
|
||||
concept HasConstBegin = requires(const T& ct) { ct.begin(); };
|
||||
|
||||
template <class T>
|
||||
concept HasBegin = requires(T& t) { t.begin(); };
|
||||
|
||||
template <class T>
|
||||
concept HasConstAndNonConstBegin = requires(T& t, const T& ct) {
|
||||
// The return types for begin are different when this is const or not:
|
||||
// the iterator's _Const non-type-template parameter is true in the former
|
||||
// and false in the latter.
|
||||
requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
// There is a begin but it's not const qualified => Only non-const qualified begin.
|
||||
concept HasOnlyNonConstBegin = HasBegin<T> && !HasConstBegin<T>;
|
||||
|
||||
template <class T>
|
||||
// There is a const-qualified begin and there are not both const- and non-const qualified begin => Only const-qualified begin.
|
||||
concept HasOnlyConstBegin = HasConstBegin<T> && !HasConstAndNonConstBegin<T>;
|
||||
|
||||
static_assert(HasOnlyNonConstBegin<std::ranges::stride_view<UnSimpleNoConstCommonView>>);
|
||||
static_assert(HasOnlyConstBegin<std::ranges::stride_view<SimpleCommonConstView>>);
|
||||
static_assert(HasConstAndNonConstBegin<std::ranges::stride_view<UnSimpleConstView>>);
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// Return type check for non-simple const view.
|
||||
const auto v = UnSimpleConstView();
|
||||
const auto sv = std::ranges::stride_view(v, 1);
|
||||
static_assert(std::same_as<decltype(*sv.begin()), double&>);
|
||||
}
|
||||
{
|
||||
// Return type check for simple const view.
|
||||
auto v = SimpleCommonConstView();
|
||||
auto sv = std::ranges::stride_view(v, 1);
|
||||
static_assert(std::same_as<decltype(*sv.begin()), int&>);
|
||||
}
|
||||
{
|
||||
// Verify begin() produces the first element with stride 1.
|
||||
int data[] = {10, 20, 30, 40, 50};
|
||||
auto v = BasicTestView<int*, int*>{data, data + 5};
|
||||
auto sv = std::ranges::stride_view(v, 1);
|
||||
assert(*sv.begin() == 10);
|
||||
}
|
||||
{
|
||||
// Verify begin() produces the first element with stride 3.
|
||||
int data[] = {10, 20, 30, 40, 50};
|
||||
auto v = BasicTestView<int*, int*>{data, data + 5};
|
||||
auto sv = std::ranges::stride_view(v, 3);
|
||||
assert(*sv.begin() == 10);
|
||||
}
|
||||
{
|
||||
// Verify iterating from begin with stride 2 produces correct elements.
|
||||
int data[] = {1, 2, 3, 4, 5};
|
||||
auto v = BasicTestView<int*, int*>{data, data + 5};
|
||||
auto sv = std::ranges::stride_view(v, 2);
|
||||
auto it = sv.begin();
|
||||
assert(*it == 1);
|
||||
++it;
|
||||
assert(*it == 3);
|
||||
++it;
|
||||
assert(*it == 5);
|
||||
++it;
|
||||
assert(it == sv.end());
|
||||
}
|
||||
{
|
||||
// Verify begin on forward range.
|
||||
int data[] = {100, 200, 300};
|
||||
using FwdView = BasicTestView<forward_iterator<int*>, forward_iterator<int*>>;
|
||||
auto v = FwdView{forward_iterator(data), forward_iterator(data + 3)};
|
||||
auto sv = std::ranges::stride_view(v, 2);
|
||||
assert(*sv.begin() == 100);
|
||||
auto it = sv.begin();
|
||||
++it;
|
||||
assert(*it == 300);
|
||||
}
|
||||
{
|
||||
// Empty range: begin() == end().
|
||||
int data[] = {1};
|
||||
auto v = BasicTestView<int*, int*>{data, data};
|
||||
auto sv = std::ranges::stride_view(v, 3);
|
||||
assert(sv.begin() == sv.end());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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<class V>
|
||||
// inline constexpr bool enable_borrowed_range<stride_view<V>> = ranges::enable_borrowed_range<V>;
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "test_range.h"
|
||||
|
||||
static_assert(std::ranges::enable_borrowed_range< std::ranges::stride_view<BorrowedView>>);
|
||||
static_assert(!std::ranges::enable_borrowed_range< std::ranges::stride_view<NonBorrowedView>>);
|
||||
@@ -0,0 +1,48 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// template <input_range V> requires view<V>
|
||||
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
|
||||
#include "almost_satisfies_types.h"
|
||||
#include "test_iterators.h"
|
||||
#include "test_range.h"
|
||||
|
||||
template <typename I, std::ranges::range_difference_t<I> D>
|
||||
concept CanStrideView = requires { std::ranges::stride_view<I>{I{}, D}; };
|
||||
|
||||
// Ensure that the InputRangeNotIndirectlyReadable is a valid range.
|
||||
static_assert(std::ranges::range<InputRangeNotIndirectlyReadable>);
|
||||
// Ensure that the InputRangeNotIndirectlyReadable's iterator is not an input range ...
|
||||
static_assert(!std::ranges::input_range<std::ranges::iterator_t<InputRangeNotIndirectlyReadable>>);
|
||||
// Because CanStrideView requires that the range/view type be default constructible, let's double check that ...
|
||||
static_assert(std::is_default_constructible_v<InputRangeNotIndirectlyReadable>);
|
||||
// And now, finally, let's make sure that we cannot stride over a range whose iterator is not an input iterator ...
|
||||
static_assert(!CanStrideView<InputRangeNotIndirectlyReadable, 1>);
|
||||
|
||||
// Ensure that a range that is not a view cannot be the subject of a stride_view.
|
||||
static_assert(std::ranges::range<test_non_const_range<cpp17_input_iterator>>);
|
||||
static_assert(std::ranges::input_range<test_non_const_range<cpp17_input_iterator>>);
|
||||
static_assert(std::movable<test_non_const_range<cpp17_input_iterator>>);
|
||||
static_assert(!std::ranges::view<test_non_const_range<cpp17_input_iterator>>);
|
||||
static_assert(!CanStrideView<test_non_const_range<cpp17_input_iterator>, 1>);
|
||||
|
||||
// And now, let's satisfy all the prerequisites and make sure that we can stride over a range (that is an input range
|
||||
// and is a view!)
|
||||
static_assert(std::ranges::range<test_view<cpp17_input_iterator>>);
|
||||
static_assert(std::ranges::input_range<test_view<cpp17_input_iterator>>);
|
||||
static_assert(std::ranges::view<test_view<cpp17_input_iterator>>);
|
||||
static_assert(CanStrideView<test_view<cpp17_input_iterator>, 1>);
|
||||
|
||||
// stride_view itself models view.
|
||||
static_assert(std::ranges::view<std::ranges::stride_view<test_view<cpp17_input_iterator>>>);
|
||||
static_assert(std::ranges::view<std::ranges::stride_view<test_view<forward_iterator>>>);
|
||||
@@ -0,0 +1,103 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 <class R>
|
||||
// stride_view(R&&, range_difference_t<R>) -> stride_view<views::all_t<R>>;
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct View : std::ranges::view_base {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
struct Range {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
int a[] = {1, 2, 3, 4, 5};
|
||||
|
||||
using BaseRange = BasicTestRange<cpp17_input_iterator<int*>>;
|
||||
using BaseView = BasicTestView<int*>;
|
||||
|
||||
auto base_view = BaseView(a, a + 5);
|
||||
auto base_view_move = BaseView(a, a + 5);
|
||||
|
||||
auto base_range = BaseRange(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 5));
|
||||
auto base_range_move = BaseRange(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 5));
|
||||
|
||||
// Deduction from lvalue view and rvalue view.
|
||||
auto sv_view = std::ranges::stride_view(base_view, 2);
|
||||
auto sv_view_move = std::ranges::stride_view(std::move(base_view_move), 2);
|
||||
|
||||
// Deduction from lvalue range (-> ref_view) and rvalue range (-> owning_view).
|
||||
auto sv_range = std::ranges::stride_view(base_range, 2);
|
||||
auto sv_range_move = std::ranges::stride_view(std::move(base_range_move), 2);
|
||||
|
||||
// Verify deduced types for views.
|
||||
static_assert(std::same_as<decltype(sv_view), std::ranges::stride_view<BaseView>>);
|
||||
static_assert(std::same_as<decltype(sv_view_move), std::ranges::stride_view<BaseView>>);
|
||||
|
||||
// Verify deduced types for ranges: lvalue -> ref_view, rvalue -> owning_view.
|
||||
static_assert(std::same_as<decltype(sv_range), std::ranges::stride_view<std::ranges::ref_view<BaseRange>> >);
|
||||
static_assert(std::same_as<decltype(sv_range_move), std::ranges::stride_view<std::ranges::owning_view<BaseRange>> >);
|
||||
|
||||
// Verify begin() produces the first element.
|
||||
assert(*sv_range.begin() == 1);
|
||||
assert(*sv_range_move.begin() == 1);
|
||||
assert(*sv_view.begin() == 1);
|
||||
assert(*sv_view_move.begin() == 1);
|
||||
|
||||
// Verify iteration with stride 2 over a range.
|
||||
auto it = sv_range.begin();
|
||||
it++;
|
||||
assert(*it == 3);
|
||||
it++;
|
||||
it++;
|
||||
assert(it == sv_range.end());
|
||||
|
||||
auto it2 = sv_range_move.begin();
|
||||
it2++;
|
||||
it2++;
|
||||
assert(*it2 == 5);
|
||||
it2++;
|
||||
assert(it2 == sv_range_move.end());
|
||||
|
||||
// Verify iteration with stride 2 over a view.
|
||||
auto it3 = sv_view.begin();
|
||||
it3++;
|
||||
assert(*it3 == 3);
|
||||
it3++;
|
||||
it3++;
|
||||
assert(it3 == sv_view.end());
|
||||
|
||||
auto it4 = sv_view.begin();
|
||||
it4++;
|
||||
it4++;
|
||||
assert(*it4 == 5);
|
||||
it4++;
|
||||
assert(it4 == sv_view_move.end());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 stride_view(V base, range_difference_t<V> stride)
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "test_convertible.h"
|
||||
#include "test_iterators.h"
|
||||
#include "types.h"
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// There is no default ctor for stride_view.
|
||||
using View = BasicTestView<cpp17_input_iterator<int*>>;
|
||||
static_assert(!std::is_default_constructible_v<std::ranges::stride_view<View>>);
|
||||
|
||||
// Test that the stride_view can only be explicitly constructed.
|
||||
static_assert(!test_convertible<std::ranges::stride_view<View>, View, int>());
|
||||
}
|
||||
|
||||
{
|
||||
int arr[] = {1, 2, 3};
|
||||
// Test that what we will stride over is move only.
|
||||
using View = MoveOnlyView<cpp17_input_iterator<int*>>;
|
||||
static_assert(!std::is_copy_constructible_v<View>);
|
||||
static_assert(std::is_move_constructible_v<View>);
|
||||
|
||||
View mov(cpp17_input_iterator<int*>(arr), cpp17_input_iterator<int*>(arr + 3));
|
||||
// Because MoveOnlyView is, well, move only, we can test that it is moved
|
||||
// from when the stride view is constructed.
|
||||
std::ranges::stride_view<View> strided(std::move(mov), 1);
|
||||
|
||||
// While we are here, make sure that the ctor captured the stride.
|
||||
assert(strided.stride() == 1);
|
||||
}
|
||||
{
|
||||
// Verify salient properties after construction.
|
||||
int arr[] = {10, 20, 30, 40, 50};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto strided = std::ranges::stride_view(Base(arr, arr + 5), 2);
|
||||
|
||||
assert(strided.stride() == 2);
|
||||
assert(*strided.begin() == 10);
|
||||
|
||||
auto it = strided.begin();
|
||||
++it;
|
||||
assert(*it == 30);
|
||||
++it;
|
||||
assert(*it == 50);
|
||||
++it;
|
||||
assert(it == strided.end());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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() requires(!simple-view<V>)
|
||||
// constexpr auto end() const requires(range<const V>)
|
||||
|
||||
// Note: Checks here are augmented by checks in
|
||||
// iterator/ctor.copy.pass.cpp.
|
||||
|
||||
#include <ranges>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "types.h"
|
||||
|
||||
// A view that is a common forward range when const, but NOT a common range when non-const.
|
||||
struct CommonForwardOnlyWhenConst : std::ranges::view_base {
|
||||
int* data_;
|
||||
int size_;
|
||||
|
||||
constexpr CommonForwardOnlyWhenConst(int* d, int s) : data_(d), size_(s) {}
|
||||
|
||||
CommonForwardOnlyWhenConst(CommonForwardOnlyWhenConst&&) = default;
|
||||
CommonForwardOnlyWhenConst& operator=(CommonForwardOnlyWhenConst&&) = default;
|
||||
|
||||
// Non-const: not a common range (iterator and sentinel are different types).
|
||||
constexpr forward_iterator<int*> begin() { return forward_iterator<int*>(data_); }
|
||||
constexpr sentinel_wrapper<forward_iterator<int*>> end() {
|
||||
return sentinel_wrapper<forward_iterator<int*>>(forward_iterator<int*>(data_ + size_));
|
||||
}
|
||||
|
||||
// Const: a common forward range (begin and end return the same type).
|
||||
constexpr forward_iterator<const int*> begin() const { return forward_iterator<const int*>(data_); }
|
||||
constexpr forward_iterator<const int*> end() const { return forward_iterator<const int*>(data_ + size_); }
|
||||
};
|
||||
|
||||
static_assert(std::ranges::range<CommonForwardOnlyWhenConst>);
|
||||
static_assert(std::ranges::range<const CommonForwardOnlyWhenConst>);
|
||||
static_assert(std::ranges::forward_range<const CommonForwardOnlyWhenConst>);
|
||||
static_assert(!std::ranges::bidirectional_range<const CommonForwardOnlyWhenConst>);
|
||||
static_assert(std::ranges::common_range<const CommonForwardOnlyWhenConst>);
|
||||
static_assert(!std::ranges::common_range<CommonForwardOnlyWhenConst>);
|
||||
static_assert(std::ranges::view<CommonForwardOnlyWhenConst>);
|
||||
|
||||
template <class T>
|
||||
concept HasConstEnd = requires(const T& ct) { ct.end(); };
|
||||
|
||||
template <class T>
|
||||
concept HasEnd = requires(T& t) { t.end(); };
|
||||
|
||||
template <class T>
|
||||
concept HasConstAndNonConstEnd =
|
||||
HasConstEnd<T> && requires(T& t, const T& ct) { requires !std::same_as<decltype(t.end()), decltype(ct.end())>; };
|
||||
|
||||
template <class T>
|
||||
concept HasOnlyNonConstEnd = HasEnd<T> && !HasConstEnd<T>;
|
||||
|
||||
template <class T>
|
||||
concept HasOnlyConstEnd = HasConstEnd<T> && !HasConstAndNonConstEnd<T>;
|
||||
|
||||
static_assert(HasOnlyNonConstEnd<std::ranges::stride_view<UnSimpleNoConstCommonView>>);
|
||||
static_assert(HasOnlyConstEnd<std::ranges::stride_view<SimpleCommonConstView>>);
|
||||
static_assert(HasConstAndNonConstEnd<std::ranges::stride_view<UnSimpleConstView>>);
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// A const, simple, common-, sized- and forward-range.
|
||||
// Note: sized because it is possible to get a difference between its
|
||||
// beginning and its end.
|
||||
const int data[] = {1, 2, 3};
|
||||
auto v = BasicTestView<const int*, const int*>{data, data + 3};
|
||||
auto sv = std::ranges::stride_view(v, 1);
|
||||
static_assert(!std::is_same_v<std::default_sentinel_t, decltype(sv.end())>);
|
||||
|
||||
// Verify actual end behavior: iterating reaches end.
|
||||
auto it = sv.begin();
|
||||
++it;
|
||||
++it;
|
||||
++it;
|
||||
assert(it == sv.end());
|
||||
}
|
||||
{
|
||||
// ForwardTestView is not sized and not bidirectional, but it is common.
|
||||
// Note: It is not sized because BasicTestView has no member function named size (by default)
|
||||
// and nor is it possible to get a difference between its beginning and its end.
|
||||
int data[] = {1, 2, 3};
|
||||
using ForwardTestView = BasicTestView<forward_iterator<int*>, forward_iterator<int*>>;
|
||||
auto v = ForwardTestView{forward_iterator(data), forward_iterator(data + 3)};
|
||||
auto sv = std::ranges::stride_view(v, 1);
|
||||
static_assert(!std::is_same_v<std::default_sentinel_t, decltype(sv.end())>);
|
||||
|
||||
auto it = sv.begin();
|
||||
++it;
|
||||
++it;
|
||||
++it;
|
||||
assert(it == sv.end());
|
||||
}
|
||||
{
|
||||
// A non-const, non-simple, common-, sized- and forward-range.
|
||||
static_assert(!simple_view<UnSimpleNoConstCommonView>);
|
||||
static_assert(std::ranges::common_range<UnSimpleNoConstCommonView>);
|
||||
static_assert(std::ranges::sized_range<UnSimpleNoConstCommonView>);
|
||||
static_assert(std::ranges::forward_range<UnSimpleNoConstCommonView>);
|
||||
|
||||
auto sv = std::ranges::stride_view<UnSimpleNoConstCommonView>(UnSimpleNoConstCommonView{}, 1);
|
||||
static_assert(!std::is_same_v<std::default_sentinel_t, decltype(sv.end())>);
|
||||
}
|
||||
{
|
||||
// Uncommon range -> returns default_sentinel.
|
||||
static_assert(!simple_view<UnsimpleUnCommonConstView>);
|
||||
static_assert(!std::ranges::common_range<UnsimpleUnCommonConstView>);
|
||||
|
||||
auto sv = std::ranges::stride_view<UnsimpleUnCommonConstView>(UnsimpleUnCommonConstView{}, 1);
|
||||
ASSERT_SAME_TYPE(std::default_sentinel_t, decltype(sv.end()));
|
||||
}
|
||||
{
|
||||
// Simple, uncommon range -> returns default_sentinel.
|
||||
static_assert(simple_view<SimpleUnCommonConstView>);
|
||||
static_assert(!std::ranges::common_range<SimpleUnCommonConstView>);
|
||||
|
||||
auto sv = std::ranges::stride_view<SimpleUnCommonConstView>(SimpleUnCommonConstView{}, 1);
|
||||
ASSERT_SAME_TYPE(std::default_sentinel_t, decltype(sv.end()));
|
||||
}
|
||||
{
|
||||
// Verify stride > 1 with end(): iterating produces correct elements and terminates.
|
||||
int data[] = {10, 20, 30, 40, 50};
|
||||
auto v = BasicTestView<int*, int*>{data, data + 5};
|
||||
auto sv = std::ranges::stride_view(v, 2);
|
||||
|
||||
auto it = sv.begin();
|
||||
assert(*it == 10);
|
||||
++it;
|
||||
assert(*it == 30);
|
||||
++it;
|
||||
assert(*it == 50);
|
||||
++it;
|
||||
assert(it == sv.end());
|
||||
}
|
||||
{
|
||||
// Verify end() with stride that doesn't evenly divide the range.
|
||||
int data[] = {1, 2, 3, 4, 5, 6, 7};
|
||||
auto v = BasicTestView<int*, int*>{data, data + 7};
|
||||
auto sv = std::ranges::stride_view(v, 3);
|
||||
|
||||
auto it = sv.begin();
|
||||
assert(*it == 1);
|
||||
++it;
|
||||
assert(*it == 4);
|
||||
++it;
|
||||
assert(*it == 7);
|
||||
++it;
|
||||
assert(it == sv.end());
|
||||
}
|
||||
{
|
||||
// end() const should use common_range<const _View>, not common_range<_View>. CommonForwardOnlyWhenConst is
|
||||
// common + forward-only when const, but NOT common when non-const.
|
||||
int data[] = {1, 2, 3, 4, 5};
|
||||
auto v = CommonForwardOnlyWhenConst(data, 5);
|
||||
auto sv = std::ranges::stride_view(std::move(v), 2);
|
||||
const auto& csv = sv;
|
||||
|
||||
// The key assertion: end() on the const stride_view must NOT return default_sentinel_t.
|
||||
static_assert(!std::is_same_v<std::default_sentinel_t, decltype(csv.end())>);
|
||||
|
||||
// Verify iteration actually works and reaches end.
|
||||
auto it = csv.begin();
|
||||
assert(*it == 1);
|
||||
++it;
|
||||
assert(*it == 3);
|
||||
++it;
|
||||
assert(*it == 5);
|
||||
++it;
|
||||
assert(it == csv.end());
|
||||
}
|
||||
{
|
||||
// Test the `common_range && forward_range && !sized_range && !bidirectional_range` branch.
|
||||
// forward_iterator<int*> does not support operator-, so the view is not sized.
|
||||
// end() should return an iterator (not default_sentinel).
|
||||
int data[] = {1, 2, 3, 4, 5};
|
||||
using FwdView = BasicTestView<forward_iterator<int*>, forward_iterator<int*>>;
|
||||
static_assert(std::ranges::common_range<FwdView>);
|
||||
static_assert(std::ranges::forward_range<FwdView>);
|
||||
static_assert(!std::ranges::bidirectional_range<FwdView>);
|
||||
static_assert(!std::ranges::sized_range<FwdView>);
|
||||
|
||||
auto v = FwdView{forward_iterator(data), forward_iterator(data + 5)};
|
||||
auto sv = std::ranges::stride_view(v, 2);
|
||||
static_assert(!std::is_same_v<std::default_sentinel_t, decltype(sv.end())>);
|
||||
|
||||
auto it = sv.begin();
|
||||
assert(*it == 1);
|
||||
++it;
|
||||
assert(*it == 3);
|
||||
++it;
|
||||
assert(*it == 5);
|
||||
++it;
|
||||
assert(it == sv.end());
|
||||
}
|
||||
{
|
||||
// Empty range: begin() == end().
|
||||
int data[] = {1};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(data, data), 3);
|
||||
assert(sv.begin() == sv.end());
|
||||
}
|
||||
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 const iterator_t<Base>& base() const& noexcept
|
||||
// constexpr iterator_t<Base> base() &&
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// base() const& is noexcept; base() && is not.
|
||||
int arr[] = {1, 2, 3};
|
||||
auto stride = std::ranges::stride_view(arr, 1);
|
||||
[[maybe_unused]] auto stride_iter = stride.begin();
|
||||
|
||||
static_assert(noexcept(stride_iter.base()));
|
||||
static_assert(!noexcept((std::move(stride_iter).base())));
|
||||
}
|
||||
{
|
||||
// base() const& returns a const ref; base() && returns a non-const value.
|
||||
int arr[] = {1, 2, 3};
|
||||
auto stride = std::ranges::stride_view(arr, 1);
|
||||
[[maybe_unused]] auto stride_iter = stride.begin();
|
||||
|
||||
static_assert(std::is_const_v<std::remove_reference_t<decltype(stride_iter.base())>>);
|
||||
static_assert(!std::is_const_v<decltype(std::move(stride_iter).base())>);
|
||||
}
|
||||
{
|
||||
// base() && moves the underlying iterator.
|
||||
int move_counter = 0;
|
||||
int copy_counter = 0;
|
||||
|
||||
auto start = SizedInputIter();
|
||||
start.move_counter = &move_counter;
|
||||
start.copy_counter = ©_counter;
|
||||
auto stop = SizedInputIter();
|
||||
|
||||
auto view = BasicTestView<SizedInputIter>{start, stop};
|
||||
assert(move_counter == 0);
|
||||
assert(copy_counter == 1);
|
||||
|
||||
auto sv = std::ranges::stride_view<BasicTestView<SizedInputIter>>(view, 1);
|
||||
assert(move_counter == 1);
|
||||
assert(copy_counter == 2);
|
||||
|
||||
auto svi = sv.begin();
|
||||
assert(copy_counter == 3);
|
||||
assert(move_counter == 2);
|
||||
|
||||
[[maybe_unused]] auto result = std::move(svi).base();
|
||||
assert(move_counter == 3);
|
||||
assert(copy_counter == 3);
|
||||
}
|
||||
{
|
||||
// base() const& copies the underlying iterator.
|
||||
int move_counter = 0;
|
||||
int copy_counter = 0;
|
||||
auto start = SizedInputIter();
|
||||
|
||||
start.move_counter = &move_counter;
|
||||
start.copy_counter = ©_counter;
|
||||
auto stop = SizedInputIter();
|
||||
|
||||
auto view = BasicTestView<SizedInputIter>{start, stop};
|
||||
assert(move_counter == 0);
|
||||
assert(copy_counter == 1);
|
||||
|
||||
auto sv = std::ranges::stride_view<BasicTestView<SizedInputIter>>(view, 1);
|
||||
assert(move_counter == 1);
|
||||
assert(copy_counter == 2);
|
||||
|
||||
[[maybe_unused]] auto svi = sv.begin();
|
||||
assert(copy_counter == 3);
|
||||
assert(move_counter == 2);
|
||||
|
||||
[[maybe_unused]] const SizedInputIter base_result = svi.base();
|
||||
assert(move_counter == 2);
|
||||
assert(copy_counter == 4);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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)
|
||||
// friend constexpr bool operator<=(const iterator& x, const iterator& y)
|
||||
// friend constexpr bool operator>=(const iterator& x, const iterator& y)
|
||||
// friend constexpr auto operator<=>(const iterator& x, const iterator& y)
|
||||
|
||||
#include <cassert>
|
||||
#include <compare>
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// Input view: no relational comparisons.
|
||||
using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
|
||||
using StrideInputIter = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
|
||||
static_assert(!std::is_invocable_v<std::less<>, StrideInputIter, StrideInputIter>);
|
||||
static_assert(!std::is_invocable_v<std::greater<>, StrideInputIter, StrideInputIter>);
|
||||
static_assert(!std::is_invocable_v<std::less_equal<>, StrideInputIter, StrideInputIter>);
|
||||
static_assert(!std::is_invocable_v<std::greater_equal<>, StrideInputIter, StrideInputIter>);
|
||||
|
||||
// Forward view: no relational comparisons.
|
||||
using FwdView = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
|
||||
using StrideFwdIter = std::ranges::iterator_t<std::ranges::stride_view<FwdView>>;
|
||||
static_assert(!std::is_invocable_v<std::less<>, StrideFwdIter, StrideFwdIter>);
|
||||
static_assert(!std::is_invocable_v<std::greater<>, StrideFwdIter, StrideFwdIter>);
|
||||
static_assert(!std::is_invocable_v<std::less_equal<>, StrideFwdIter, StrideFwdIter>);
|
||||
static_assert(!std::is_invocable_v<std::greater_equal<>, StrideFwdIter, StrideFwdIter>);
|
||||
|
||||
// Bidirectional view: no relational comparisons.
|
||||
using BidirView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
|
||||
using StrideBidirIter = std::ranges::iterator_t<std::ranges::stride_view<BidirView>>;
|
||||
static_assert(!std::is_invocable_v<std::less<>, StrideBidirIter, StrideBidirIter>);
|
||||
static_assert(!std::is_invocable_v<std::greater<>, StrideBidirIter, StrideBidirIter>);
|
||||
static_assert(!std::is_invocable_v<std::less_equal<>, StrideBidirIter, StrideBidirIter>);
|
||||
static_assert(!std::is_invocable_v<std::greater_equal<>, StrideBidirIter, StrideBidirIter>);
|
||||
|
||||
// Random access view: all relational comparisons available.
|
||||
using RAView = BasicTestView<random_access_iterator<int*>>;
|
||||
using StrideRAIter = std::ranges::iterator_t<std::ranges::stride_view<RAView>>;
|
||||
static_assert(std::is_invocable_v<std::less<>, StrideRAIter, StrideRAIter>);
|
||||
static_assert(std::is_invocable_v<std::greater<>, StrideRAIter, StrideRAIter>);
|
||||
static_assert(std::is_invocable_v<std::less_equal<>, StrideRAIter, StrideRAIter>);
|
||||
static_assert(std::is_invocable_v<std::greater_equal<>, StrideRAIter, StrideRAIter>);
|
||||
|
||||
// three_way_comparable when the base iterator is three_way_comparable.
|
||||
using ThreeWayView = BasicTestView<three_way_contiguous_iterator<int*>>;
|
||||
using StrideThreeWayIter = std::ranges::iterator_t<std::ranges::stride_view<ThreeWayView>>;
|
||||
static_assert(std::three_way_comparable<StrideThreeWayIter>);
|
||||
|
||||
// Not three_way_comparable when the base is not.
|
||||
using EqualOnlyView = BasicTestView<cpp17_input_iterator<int*>>;
|
||||
using StrideEqualOnlyIter = std::ranges::iterator_t<std::ranges::stride_view<EqualOnlyView>>;
|
||||
static_assert(!std::three_way_comparable<StrideEqualOnlyIter>);
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// <, >, <=, >= on random access range.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 9), 3);
|
||||
|
||||
auto a = sv.begin(); // index 0
|
||||
auto b = sv.begin();
|
||||
++b; // index 3
|
||||
auto c = sv.begin();
|
||||
++c;
|
||||
++c; // index 6
|
||||
|
||||
assert(a < b);
|
||||
assert(b < c);
|
||||
assert(!(b < a));
|
||||
assert(!(a < a));
|
||||
|
||||
assert(b > a);
|
||||
assert(c > b);
|
||||
assert(!(a > b));
|
||||
assert(!(a > a));
|
||||
|
||||
assert(a <= b);
|
||||
assert(a <= a);
|
||||
assert(!(b <= a));
|
||||
|
||||
assert(b >= a);
|
||||
assert(a >= a);
|
||||
assert(!(a >= b));
|
||||
}
|
||||
{
|
||||
// <=> on three_way_comparable base.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7};
|
||||
using Base = BasicTestView<three_way_contiguous_iterator<int*>, three_way_contiguous_iterator<int*>>;
|
||||
auto sv =
|
||||
std::ranges::stride_view(Base(three_way_contiguous_iterator(arr), three_way_contiguous_iterator(arr + 7)), 2);
|
||||
|
||||
auto a = sv.begin();
|
||||
auto b = sv.begin();
|
||||
++b;
|
||||
|
||||
assert((a <=> b) == std::strong_ordering::less);
|
||||
assert((b <=> a) == std::strong_ordering::greater);
|
||||
assert((a <=> a) == std::strong_ordering::equal);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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<iterator_t<V>, iterator_t<Base>> &&
|
||||
// convertible_to<sentinel_t<V>, sentinel_t<Base>>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
// A non-simple view over actual data. begin()/end() return int* when non-const
|
||||
// and const int* when const, so iterator<false> and iterator<true> are distinct
|
||||
// and the converting constructor is available (int* converts to const int*).
|
||||
struct NonSimpleDataView : std::ranges::view_base {
|
||||
int* data_;
|
||||
int size_;
|
||||
|
||||
constexpr NonSimpleDataView(int* d, int s) : data_(d), size_(s) {}
|
||||
NonSimpleDataView(NonSimpleDataView&&) = default;
|
||||
NonSimpleDataView& operator=(NonSimpleDataView&&) = default;
|
||||
|
||||
constexpr int* begin() { return data_; }
|
||||
constexpr const int* begin() const { return data_; }
|
||||
constexpr int* end() { return data_ + size_; }
|
||||
constexpr const int* end() const { return data_ + size_; }
|
||||
};
|
||||
|
||||
static_assert(!simple_view<NonSimpleDataView>);
|
||||
|
||||
// Two unrelated input iterator types (no conversion between them).
|
||||
struct IterA : InputIter<IterA> {};
|
||||
struct IterB : InputIter<IterB> {
|
||||
friend constexpr bool operator==(const IterB&, const IterA&) { return true; }
|
||||
};
|
||||
|
||||
// Two unrelated sentinel types (no conversion between them).
|
||||
struct SentA {
|
||||
friend constexpr bool operator==(const SentA&, const IterA&) { return true; }
|
||||
friend constexpr bool operator==(const SentA&, const IterB&) { return true; }
|
||||
};
|
||||
struct SentB {
|
||||
friend constexpr bool operator==(const SentB&, const IterA&) { return true; }
|
||||
friend constexpr bool operator==(const SentB&, const IterB&) { return true; }
|
||||
};
|
||||
|
||||
// Non-simple view where iterator conversion fails (IterA does not convert to IterB).
|
||||
struct IterNonConvertibleView : std::ranges::view_base {
|
||||
constexpr IterA begin() { return {}; }
|
||||
constexpr IterB begin() const { return {}; }
|
||||
constexpr SentA end() const { return {}; }
|
||||
};
|
||||
|
||||
// Non-simple view where sentinel conversion fails (SentA does not convert to SentB).
|
||||
struct SentNonConvertibleView : std::ranges::view_base {
|
||||
constexpr IterA begin() const { return {}; }
|
||||
constexpr SentA end() { return {}; }
|
||||
constexpr SentB end() const { return {}; }
|
||||
};
|
||||
|
||||
// Conversion succeeds: both iterator and sentinel types are convertible (int* -> const int*).
|
||||
using ConvertibleSV = std::ranges::stride_view<NonSimpleDataView>;
|
||||
using ConvertibleIter = std::ranges::iterator_t<ConvertibleSV>;
|
||||
using ConvertibleCIter = std::ranges::iterator_t<const ConvertibleSV>;
|
||||
static_assert(!std::same_as<ConvertibleIter, ConvertibleCIter>);
|
||||
static_assert(std::convertible_to<ConvertibleIter, ConvertibleCIter>);
|
||||
static_assert(std::constructible_from<ConvertibleCIter, ConvertibleIter>);
|
||||
|
||||
// Conversion fails: underlying iterator types are not convertible (IterA -> IterB).
|
||||
using IterNCSV = std::ranges::stride_view<IterNonConvertibleView>;
|
||||
using IterNCIter = std::ranges::iterator_t<IterNCSV>;
|
||||
using IterNCCIter = std::ranges::iterator_t<const IterNCSV>;
|
||||
static_assert(!std::same_as<IterNCIter, IterNCCIter>);
|
||||
static_assert(!std::convertible_to<IterNCIter, IterNCCIter>);
|
||||
static_assert(!std::constructible_from<IterNCCIter, IterNCIter>);
|
||||
|
||||
// Conversion fails: underlying sentinel types are not convertible (SentA -> SentB).
|
||||
using SentNCSV = std::ranges::stride_view<SentNonConvertibleView>;
|
||||
using SentNCIter = std::ranges::iterator_t<SentNCSV>;
|
||||
using SentNCCIter = std::ranges::iterator_t<const SentNCSV>;
|
||||
static_assert(!std::same_as<SentNCIter, SentNCCIter>);
|
||||
static_assert(!std::convertible_to<SentNCIter, SentNCCIter>);
|
||||
static_assert(!std::constructible_from<SentNCCIter, SentNCIter>);
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// Convert non-const iterator to const iterator with stride 1.
|
||||
int arr[] = {10, 20, 30, 40, 50};
|
||||
auto sv = ConvertibleSV(NonSimpleDataView(arr, 5), 1);
|
||||
auto it = sv.begin();
|
||||
assert(*it == 10);
|
||||
|
||||
ConvertibleCIter cit{it};
|
||||
assert(*cit == 10);
|
||||
|
||||
++cit;
|
||||
assert(*cit == 20);
|
||||
++cit;
|
||||
assert(*cit == 30);
|
||||
++cit;
|
||||
assert(*cit == 40);
|
||||
++cit;
|
||||
assert(*cit == 50);
|
||||
++cit;
|
||||
assert(cit == std::as_const(sv).end());
|
||||
}
|
||||
{
|
||||
// Convert non-const iterator to const iterator with stride 2.
|
||||
int arr[] = {10, 20, 30, 40, 50};
|
||||
auto sv = ConvertibleSV(NonSimpleDataView(arr, 5), 2);
|
||||
auto it = sv.begin();
|
||||
|
||||
ConvertibleCIter cit{it};
|
||||
assert(*cit == 10);
|
||||
++cit;
|
||||
assert(*cit == 30);
|
||||
++cit;
|
||||
assert(*cit == 50);
|
||||
++cit;
|
||||
assert(cit == std::as_const(sv).end());
|
||||
}
|
||||
{
|
||||
// Convert after advancing the non-const iterator.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
auto sv = ConvertibleSV(NonSimpleDataView(arr, 9), 3);
|
||||
auto it = sv.begin();
|
||||
++it;
|
||||
assert(*it == 4);
|
||||
|
||||
ConvertibleCIter cit{it};
|
||||
assert(*cit == 4);
|
||||
++cit;
|
||||
assert(*cit == 7);
|
||||
++cit;
|
||||
assert(cit == std::as_const(sv).end());
|
||||
}
|
||||
{
|
||||
// Convert with stride larger than range size.
|
||||
int arr[] = {42, 99};
|
||||
auto sv = ConvertibleSV(NonSimpleDataView(arr, 2), 5);
|
||||
auto it = sv.begin();
|
||||
|
||||
ConvertibleCIter cit{it};
|
||||
assert(*cit == 42);
|
||||
++cit;
|
||||
assert(cit == std::as_const(sv).end());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// iterator() requires default_initializable<iterator_t<Base>> = default;
|
||||
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
struct NonDefaultConstructibleIterator : InputIter<NonDefaultConstructibleIterator> {
|
||||
NonDefaultConstructibleIterator() = delete;
|
||||
constexpr NonDefaultConstructibleIterator(int) {}
|
||||
};
|
||||
|
||||
struct ViewWithNonDefaultConstructibleIterator : std::ranges::view_base {
|
||||
constexpr NonDefaultConstructibleIterator begin() const { return NonDefaultConstructibleIterator{5}; }
|
||||
constexpr std::default_sentinel_t end() const { return {}; }
|
||||
};
|
||||
template <>
|
||||
inline constexpr bool std::ranges::enable_borrowed_range<ViewWithNonDefaultConstructibleIterator> = true;
|
||||
|
||||
// The stride_view iterator is default-constructible iff the iterator type of the range being
|
||||
// strided is default-constructible.
|
||||
static_assert(!std::is_default_constructible< std::ranges::iterator_t<ViewWithNonDefaultConstructibleIterator>>());
|
||||
static_assert(std::is_default_constructible<
|
||||
std::ranges::iterator_t< std::ranges::stride_view<std::ranges::ref_view<const int[3]>>>>());
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// Default construct an iterator over a default-constructible base.
|
||||
using SV = std::ranges::stride_view<std::ranges::ref_view<const int[3]>>;
|
||||
using It = std::ranges::iterator_t<SV>;
|
||||
[[maybe_unused]] It it{};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 <cassert>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
template <class T>
|
||||
concept CanPostDecrement = std::is_same_v<T, decltype(std::declval<T>()--)> && requires(T& t) { t--; };
|
||||
template <class T>
|
||||
concept CanPreDecrement = std::is_same_v<T, decltype(--(std::declval<T>()))> && requires(T& t) { --t; };
|
||||
|
||||
// What operators are valid for an iterator derived from a stride view
|
||||
// over an input view.
|
||||
using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
|
||||
using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
|
||||
|
||||
static_assert(!std::ranges::bidirectional_range<InputView>);
|
||||
static_assert(!CanPostDecrement<StrideViewOverInputViewIterator>);
|
||||
static_assert(!CanPreDecrement<StrideViewOverInputViewIterator>);
|
||||
|
||||
// What operators are valid for an iterator derived from a stride view
|
||||
// over a forward view.
|
||||
using ForwardView = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
|
||||
using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
|
||||
|
||||
static_assert(!std::ranges::bidirectional_range<ForwardView>);
|
||||
static_assert(!CanPostDecrement<StrideViewOverForwardViewIterator>);
|
||||
static_assert(!CanPostDecrement<StrideViewOverForwardViewIterator>);
|
||||
|
||||
// What operators are valid for an iterator derived from a stride view
|
||||
// over a bidirectional view.
|
||||
using BidirectionalView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
|
||||
using StrideViewOverBidirectionalViewIterator = std::ranges::iterator_t<std::ranges::stride_view<BidirectionalView>>;
|
||||
|
||||
static_assert(std::ranges::bidirectional_range<BidirectionalView>);
|
||||
static_assert(CanPostDecrement<StrideViewOverBidirectionalViewIterator>);
|
||||
static_assert(CanPostDecrement<StrideViewOverBidirectionalViewIterator>);
|
||||
|
||||
// What operators are valid for an iterator derived from a stride view
|
||||
// over a random access view.
|
||||
using RandomAccessView = BasicTestView<random_access_iterator<int*>>;
|
||||
using StrideViewOverRandomAccessViewIterator = std::ranges::iterator_t<std::ranges::stride_view<RandomAccessView>>;
|
||||
|
||||
static_assert(std::ranges::bidirectional_range<RandomAccessView>);
|
||||
static_assert(CanPostDecrement<StrideViewOverRandomAccessViewIterator>);
|
||||
static_assert(CanPostDecrement<StrideViewOverRandomAccessViewIterator>);
|
||||
|
||||
template <typename Iter, typename Difference>
|
||||
requires(std::bidirectional_iterator<Iter>)
|
||||
constexpr bool test_operator_decrement(Iter begin, Iter end, Difference delta) {
|
||||
using Base = BasicTestView<Iter, Iter>;
|
||||
|
||||
auto base_view_offset_zero = Base(begin, end);
|
||||
// Because of the requires on the Iter template type, we are sure
|
||||
// that the type of sv_incr_one is a bidirectional range.
|
||||
auto sv_incr_diff = std::ranges::stride_view(base_view_offset_zero, delta);
|
||||
auto sv_incr_end = sv_incr_diff.end();
|
||||
|
||||
// Recreate the "missing" calculation here -- to make sure that it matches.
|
||||
auto missing = delta - (std::ranges::distance(base_view_offset_zero) % delta) % delta;
|
||||
|
||||
auto sought = end + (missing - delta);
|
||||
|
||||
assert(*sought == *(--sv_incr_end));
|
||||
assert(*sought == *(sv_incr_end));
|
||||
|
||||
sv_incr_end = sv_incr_diff.end();
|
||||
sv_incr_end--;
|
||||
assert(*(end + (missing - delta)) == *(sv_incr_end));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// Pre-decrement and post-decrement from end with stride 3.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
test_operator_decrement(arr, arr + 11, 3);
|
||||
}
|
||||
{
|
||||
// Decrement from end when size % stride != 0.
|
||||
// 10 elements, stride 3: strided elements at indices 0,3,6,9.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 10), 3);
|
||||
auto it = sv.end();
|
||||
--it;
|
||||
assert(*it == 10); // index 9
|
||||
--it;
|
||||
assert(*it == 7); // index 6
|
||||
--it;
|
||||
assert(*it == 4); // index 3
|
||||
--it;
|
||||
assert(*it == 1); // index 0
|
||||
assert(it == sv.begin());
|
||||
}
|
||||
{
|
||||
// Decrement when stride evenly divides range size.
|
||||
// 9 elements, stride 3: strided elements at 0,3,6.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 9), 3);
|
||||
auto it = sv.end();
|
||||
--it;
|
||||
assert(*it == 7); // index 6
|
||||
--it;
|
||||
assert(*it == 4); // index 3
|
||||
--it;
|
||||
assert(*it == 1); // index 0
|
||||
}
|
||||
{
|
||||
// Decrement from mid-range position (not end).
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 10), 3);
|
||||
auto it = sv.begin();
|
||||
++it; // index 3
|
||||
++it; // index 6
|
||||
assert(*it == 7);
|
||||
--it; // back to index 3
|
||||
assert(*it == 4);
|
||||
--it; // back to index 0
|
||||
assert(*it == 1);
|
||||
}
|
||||
{
|
||||
// Round-trip: decrement from end, increment, decrement again.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 7), 3);
|
||||
auto it = sv.end();
|
||||
--it;
|
||||
assert(*it == 7); // index 6
|
||||
++it;
|
||||
assert(it == sv.end());
|
||||
--it;
|
||||
assert(*it == 7); // back to index 6 again
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// Dereference with stride 1.
|
||||
int arr[] = {10, 20, 30};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 3), 1);
|
||||
auto it = sv.begin();
|
||||
|
||||
assert(*it == 10);
|
||||
++it;
|
||||
assert(*it == 20);
|
||||
++it;
|
||||
assert(*it == 30);
|
||||
}
|
||||
{
|
||||
// Dereference with stride 2.
|
||||
int arr[] = {10, 20, 30, 40, 50};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 5), 2);
|
||||
auto it = sv.begin();
|
||||
|
||||
assert(*it == 10);
|
||||
++it;
|
||||
assert(*it == 30);
|
||||
++it;
|
||||
assert(*it == 50);
|
||||
}
|
||||
{
|
||||
// Dereference with stride larger than range.
|
||||
int arr[] = {42, 99};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 2), 5);
|
||||
auto it = sv.begin();
|
||||
|
||||
assert(*it == 42);
|
||||
}
|
||||
{
|
||||
// Dereference returns a reference that can be assigned through.
|
||||
int arr[] = {1, 2, 3, 4, 5};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 5), 2);
|
||||
auto it = sv.begin();
|
||||
|
||||
*it = 100;
|
||||
assert(arr[0] == 100);
|
||||
++it;
|
||||
*it = 200;
|
||||
assert(arr[2] == 200);
|
||||
}
|
||||
{
|
||||
// Dereference on a forward range with stride 3.
|
||||
int arr[] = {5, 10, 15, 20, 25, 30};
|
||||
using Base = BasicTestView<forward_iterator<int*>, forward_iterator<int*>>;
|
||||
auto sv = std::ranges::stride_view(Base(forward_iterator(arr), forward_iterator(arr + 6)), 3);
|
||||
auto it = sv.begin();
|
||||
assert(*it == 5);
|
||||
++it;
|
||||
assert(*it == 20);
|
||||
}
|
||||
{
|
||||
// Return type is a reference, not a value.
|
||||
int arr[] = {1, 2, 3};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 3), 1);
|
||||
auto it = sv.begin();
|
||||
static_assert(std::is_same_v<decltype(*it), int&>);
|
||||
}
|
||||
{
|
||||
// Dereference through a const-qualified iterator.
|
||||
int arr[] = {10, 20, 30};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 3), 2);
|
||||
const auto cit = sv.begin();
|
||||
assert(*cit == 10);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// friend constexpr bool operator==(const iterator& x, default_sentinel_t)
|
||||
// friend constexpr bool operator==(const iterator& x, const iterator& y)
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// A stride_view iterator over an equality_comparable base should itself be equality_comparable.
|
||||
using EqualableView = BasicTestView<cpp17_input_iterator<int*>>;
|
||||
using EqualableViewIter = std::ranges::iterator_t<std::ranges::stride_view<EqualableView>>;
|
||||
static_assert(std::equality_comparable<std::ranges::iterator_t<EqualableView>>);
|
||||
static_assert(std::equality_comparable<EqualableViewIter>);
|
||||
|
||||
// A stride_view iterator over a non-equality_comparable base should NOT be equality_comparable.
|
||||
using UnEqualableView = ViewOverNonCopyableIterator<cpp20_input_iterator<int*>>;
|
||||
using UnEqualableViewIter = std::ranges::iterator_t<std::ranges::stride_view<UnEqualableView>>;
|
||||
static_assert(!std::equality_comparable<std::ranges::iterator_t<UnEqualableView>>);
|
||||
static_assert(!std::equality_comparable<UnEqualableViewIter>);
|
||||
|
||||
template <class Iter>
|
||||
constexpr void testOne() {
|
||||
using Range = BasicTestView<Iter, Iter>;
|
||||
static_assert(std::ranges::common_range<Range>);
|
||||
using StrideView = std::ranges::stride_view<Range>;
|
||||
|
||||
{
|
||||
// Equality and inequality between iterators, and comparison with end.
|
||||
{
|
||||
int buffer[] = {0, 1, 2, -1, 4, 5, 6, 7};
|
||||
const Range input(Iter{buffer}, Iter{buffer + 8});
|
||||
const StrideView sv(input, 1);
|
||||
const StrideView sv_too(input, 2);
|
||||
auto b = sv.begin();
|
||||
auto e = sv.end();
|
||||
auto b_too = sv_too.begin();
|
||||
|
||||
assert(b == b);
|
||||
assert(!(b != b));
|
||||
|
||||
// When Range is a bidirectional_range, the type of e is
|
||||
// default_sentinel_t and those do not compare to one another.
|
||||
if constexpr (!std::ranges::bidirectional_range<Range>) {
|
||||
assert(e == e);
|
||||
assert(!(e != e));
|
||||
}
|
||||
assert(!(b == e));
|
||||
assert(b != e);
|
||||
|
||||
std::advance(b, 8);
|
||||
std::advance(b_too, 4);
|
||||
|
||||
assert(b == b_too);
|
||||
assert(!(b != b_too));
|
||||
|
||||
assert(b == b);
|
||||
assert(!(b != b));
|
||||
|
||||
// See above.
|
||||
if constexpr (!std::ranges::bidirectional_range<Range>) {
|
||||
assert(e == e);
|
||||
assert(!(e != e));
|
||||
}
|
||||
|
||||
assert(b == e);
|
||||
assert(!(b != e));
|
||||
}
|
||||
|
||||
// Default-constructed iterators compare equal.
|
||||
{
|
||||
int buffer[] = {0, 1, 2, -1, 4, 5, 6};
|
||||
const Range input(Iter{buffer}, Iter{buffer + 7});
|
||||
const std::ranges::stride_view sv(input, 1);
|
||||
using StrideViewIter = decltype(sv.begin());
|
||||
StrideViewIter i1;
|
||||
StrideViewIter i2;
|
||||
assert(i1 == i2);
|
||||
assert(!(i1 != i2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
testOne<forward_iterator<int*>>();
|
||||
testOne<bidirectional_iterator<int*>>();
|
||||
testOne<random_access_iterator<int*>>();
|
||||
testOne<contiguous_iterator<int*>>();
|
||||
testOne<int*>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 void operator++(int)
|
||||
// constexpr iterator operator++(int)
|
||||
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
template <class T>
|
||||
concept CanPostIncrementVoid = std::is_same_v<void, decltype(std::declval<T>()++)> && requires(T& t) { t++; };
|
||||
template <class T>
|
||||
concept CanPostIncrementIterator = std::is_same_v<T, decltype(std::declval<T>()++)> && requires(T& t) { t = t++; };
|
||||
template <class T>
|
||||
concept CanPreIncrementIterator = std::is_same_v<T&, decltype(++(std::declval<T>()))> && requires(T& t) { t = ++t; };
|
||||
|
||||
// A stride view with a base that is a non forward range returns void from operator++
|
||||
using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
|
||||
using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
|
||||
static_assert(CanPostIncrementVoid<StrideViewOverInputViewIterator>);
|
||||
static_assert(!CanPostIncrementIterator<StrideViewOverInputViewIterator>);
|
||||
static_assert(CanPreIncrementIterator<StrideViewOverInputViewIterator>);
|
||||
|
||||
// A stride view with a base that is a forward range returns void from operator++
|
||||
using ForwardView = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
|
||||
using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
|
||||
static_assert(!CanPostIncrementVoid<StrideViewOverForwardViewIterator>);
|
||||
static_assert(CanPostIncrementIterator<StrideViewOverForwardViewIterator>);
|
||||
static_assert(CanPreIncrementIterator<StrideViewOverForwardViewIterator>);
|
||||
|
||||
template <typename Iter>
|
||||
requires std::sized_sentinel_for<Iter, Iter> && (!std::forward_iterator<Iter>)
|
||||
constexpr bool test_non_forward_operator_increment(Iter zero_begin, Iter three_begin, Iter end) {
|
||||
using Base = BasicTestView<Iter, Iter>;
|
||||
|
||||
auto base = Base(zero_begin, end);
|
||||
auto base_offset = Base(three_begin, end);
|
||||
auto sv = std::ranges::stride_view(base, 3);
|
||||
auto sv_offset = std::ranges::stride_view(base_offset, 3);
|
||||
|
||||
auto it = sv.begin();
|
||||
auto it_offset = sv_offset.begin();
|
||||
|
||||
auto it_after = it; // With a stride of 3, so ++ moves 3 indexes.
|
||||
++it_after;
|
||||
assert(*it_offset == *it_after);
|
||||
|
||||
it_after = it;
|
||||
it_after++;
|
||||
assert(*it_offset == *it_after);
|
||||
|
||||
// See if both get to the end (with pre-increment).
|
||||
auto it_to_end = it;
|
||||
++it_to_end; // 3
|
||||
++it_to_end; // 6
|
||||
++it_to_end; // 9
|
||||
++it_to_end; // End
|
||||
|
||||
auto it_offset_to_end = it_offset; // With a stride of 3, so ++ moves 3 indexes.
|
||||
++it_offset_to_end; // 6
|
||||
++it_offset_to_end; // 9
|
||||
++it_offset_to_end; // End
|
||||
|
||||
assert(it_offset_to_end == it_to_end);
|
||||
assert(it_offset_to_end == sv_offset.end());
|
||||
assert(it_to_end == sv.end());
|
||||
|
||||
// See if both get to the end (with post-increment).
|
||||
it_to_end = it;
|
||||
it_to_end++; // 3
|
||||
it_to_end++; // 6
|
||||
it_to_end++; // 9
|
||||
it_to_end++; // End
|
||||
|
||||
it_offset_to_end = it_offset; // With a stride of 3, so ++ moves 3 indexes.
|
||||
it_offset_to_end++; // 6
|
||||
it_offset_to_end++; // 9
|
||||
it_offset_to_end++; // End
|
||||
|
||||
assert(it_offset_to_end == it_to_end);
|
||||
assert(it_offset_to_end == sv_offset.end());
|
||||
assert(it_to_end == sv.end());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <std::forward_iterator Iter>
|
||||
constexpr bool test_forward_operator_increment(Iter begin, Iter end) {
|
||||
using Base = BasicTestView<Iter, Iter>;
|
||||
|
||||
using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<Base>>;
|
||||
static_assert(std::ranges::forward_range<Base>);
|
||||
static_assert(std::weakly_incrementable<StrideViewIterator>);
|
||||
|
||||
auto base = Base(begin, end);
|
||||
auto sv = std::ranges::stride_view(base, 3);
|
||||
auto it = sv.begin();
|
||||
|
||||
// Create a ground truth for comparison.
|
||||
auto expected = sv.begin();
|
||||
expected++;
|
||||
|
||||
auto it_after = ++it;
|
||||
assert(*it_after == *it);
|
||||
assert(*it_after == *expected);
|
||||
|
||||
it = sv.begin();
|
||||
it_after = it;
|
||||
it_after++;
|
||||
assert(*it_after == *expected);
|
||||
|
||||
it = sv.begin();
|
||||
auto it_to_end = it;
|
||||
++it_to_end; // 3
|
||||
++it_to_end; // 6
|
||||
++it_to_end; // 9
|
||||
++it_to_end; // End
|
||||
|
||||
auto it_to_end2 = it; // With a stride of 3, so ++ moves 3 indexes.
|
||||
it_to_end2 = ++it_to_end2; // 3
|
||||
it_to_end2 = ++it_to_end2; // 6
|
||||
it_to_end2 = ++it_to_end2; // 9
|
||||
it_to_end2 = ++it_to_end2; // End
|
||||
|
||||
assert(it_to_end == it_to_end2);
|
||||
assert(it_to_end == sv.end());
|
||||
|
||||
it_to_end = it;
|
||||
it_to_end++; // 3
|
||||
it_to_end++; // 6
|
||||
it_to_end++; // 9
|
||||
it_to_end++; // End
|
||||
assert(it_to_end == sv.end());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test_properly_handling_missing() {
|
||||
// Check whether the "missing" distance to the end gets handled properly.
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
auto base = Base(arr, arr + 10);
|
||||
auto strider = std::ranges::stride_view<Base>(base, 7);
|
||||
|
||||
auto strider_iter = strider.end();
|
||||
|
||||
strider_iter--;
|
||||
assert(*strider_iter == 8);
|
||||
|
||||
// Now that we are back among the valid, we should
|
||||
// have a normal stride length back (i.e., there is no
|
||||
// gap between the last stride and the end).
|
||||
strider_iter--;
|
||||
assert(*strider_iter == 1);
|
||||
|
||||
strider_iter++;
|
||||
assert(*strider_iter == 8);
|
||||
|
||||
// By striding past the end, we are going to generate
|
||||
// another gap between the last stride and the end.
|
||||
strider_iter++;
|
||||
assert(strider_iter == strider.end());
|
||||
|
||||
// Make sure that all sentinel operations work!
|
||||
assert(strider.end() == std::default_sentinel);
|
||||
assert(std::default_sentinel == strider.end());
|
||||
|
||||
assert(strider_iter - std::default_sentinel == 0);
|
||||
assert(std::default_sentinel - strider.end() == 0);
|
||||
assert(std::default_sentinel - strider_iter == 0);
|
||||
|
||||
// Let's make sure that the newly regenerated gap gets used.
|
||||
strider_iter += -2;
|
||||
assert(*strider_iter == 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
test_forward_operator_increment(arr, arr + 11);
|
||||
}
|
||||
test_properly_handling_missing();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
// Non-forward iterators can't be tested in a constexpr context.
|
||||
{
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
test_non_forward_operator_increment(SizedInputIter(arr), SizedInputIter(arr + 3), SizedInputIter(arr + 10));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 range_rvalue_reference_t<Base> iter_move(const iterator& i)
|
||||
// noexcept(noexcept(ranges::iter_move(i.current_)))
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <typename T>
|
||||
concept iter_moveable = requires(T&& t) { std::ranges::iter_move(t); };
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// iter_move with a noexcept iter_move on the base iterator.
|
||||
int a[] = {4, 3, 2, 1};
|
||||
|
||||
int iter_move_counter(0);
|
||||
using View = IterMoveIterSwapTestRange<int*, /*IsSwappable=*/true, /*IsNoExcept=*/true>;
|
||||
using StrideView = std::ranges::stride_view<View>;
|
||||
auto svb = StrideView(View(a, a + 4, &iter_move_counter), 1).begin();
|
||||
|
||||
static_assert(iter_moveable<std::ranges::iterator_t<StrideView>>);
|
||||
ASSERT_SAME_TYPE(int, decltype(std::ranges::iter_move(svb)));
|
||||
static_assert(noexcept(std::ranges::iter_move(svb)));
|
||||
|
||||
auto&& result = std::ranges::iter_move(svb);
|
||||
assert(iter_move_counter == 1);
|
||||
assert(result == 4);
|
||||
|
||||
svb++;
|
||||
result = std::ranges::iter_move(svb);
|
||||
assert(iter_move_counter == 2);
|
||||
assert(result == 3);
|
||||
}
|
||||
|
||||
{
|
||||
// iter_move with a potentially-throwing iter_move on the base iterator.
|
||||
int a[] = {1, 2, 3, 4};
|
||||
|
||||
int iter_move_counter(0);
|
||||
using View = IterMoveIterSwapTestRange<int*, /*IsSwappable=*/true, /*IsNoExcept=*/false>;
|
||||
using StrideView = std::ranges::stride_view<View>;
|
||||
auto svb = StrideView(View(a, a + 4, &iter_move_counter), 1).begin();
|
||||
|
||||
static_assert(iter_moveable<std::ranges::iterator_t<StrideView>>);
|
||||
ASSERT_SAME_TYPE(int, decltype(std::ranges::iter_move(svb)));
|
||||
static_assert(!noexcept(std::ranges::iter_move(svb)));
|
||||
|
||||
auto&& result = std::ranges::iter_move(svb);
|
||||
assert(iter_move_counter == 1);
|
||||
assert(result == 1);
|
||||
|
||||
svb++;
|
||||
result = std::ranges::iter_move(svb);
|
||||
assert(iter_move_counter == 2);
|
||||
assert(result == 2);
|
||||
}
|
||||
|
||||
{
|
||||
// iter_move with a non-pointer base iterator (vector::iterator).
|
||||
std::vector<int> a = {4, 5, 6, 7, 8};
|
||||
|
||||
int iter_move_counter(0);
|
||||
using View = IterMoveIterSwapTestRange<std::vector<int>::iterator, /*IsSwappable=*/true, /*IsNoExcept=*/false>;
|
||||
|
||||
using StrideView = std::ranges::stride_view<View>;
|
||||
auto svb = StrideView(View(a.begin(), a.end(), &iter_move_counter), 1).begin();
|
||||
|
||||
static_assert(!noexcept(std::ranges::iter_move(svb)));
|
||||
|
||||
auto&& result = std::ranges::iter_move(svb);
|
||||
assert(iter_move_counter == 1);
|
||||
assert(result == 4);
|
||||
|
||||
svb++;
|
||||
result = std::ranges::iter_move(svb);
|
||||
assert(iter_move_counter == 2);
|
||||
assert(result == 5);
|
||||
}
|
||||
|
||||
{
|
||||
// Verify return type is a rvalue-reference.
|
||||
int a[] = {1, 2, 3};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(a, a + 3), 1);
|
||||
auto it = sv.begin();
|
||||
static_assert(std::is_same_v<decltype(std::ranges::iter_move(it)), int&&>);
|
||||
assert(std::ranges::iter_move(it) == 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// friend constexpr void iter_swap(const iterator& x, const iterator& y)
|
||||
// noexcept(noexcept(ranges::iter_swap(x.current_, y.current_)))
|
||||
// requires indirectly_swappable<iterator_t<Base>>
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
template <typename T>
|
||||
concept Swappable = requires(T&& t, T&& u) { std::ranges::iter_swap(t, u); };
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// iter_swap with a noexcept iter_swap on the base iterator.
|
||||
int a[] = {1, 2, 3, 4};
|
||||
int b[] = {5, 6, 7, 8};
|
||||
|
||||
int iter_move_counter_one(0);
|
||||
int iter_move_counter_two(0);
|
||||
using View = IterMoveIterSwapTestRange<int*, /*IsSwappable=*/true, /*IsNoExcept=*/true>;
|
||||
using StrideView = std::ranges::stride_view<View>;
|
||||
auto svba = StrideView(View(a, a + 4, &iter_move_counter_one), 1).begin();
|
||||
auto svbb = StrideView(View(b, b + 4, &iter_move_counter_two), 1).begin();
|
||||
|
||||
static_assert(Swappable<std::ranges::iterator_t<StrideView>>);
|
||||
static_assert(noexcept(std::ranges::iter_swap(svba, svbb)));
|
||||
|
||||
assert(a[0] == 1);
|
||||
assert(b[0] == 5);
|
||||
|
||||
std::ranges::iter_swap(svba, svbb);
|
||||
assert(iter_move_counter_one == 1);
|
||||
assert(iter_move_counter_two == 1);
|
||||
|
||||
assert(a[0] == 5);
|
||||
assert(b[0] == 1);
|
||||
}
|
||||
|
||||
{
|
||||
// iter_swap with a potentially-throwing iter_swap on the base iterator.
|
||||
int a[] = {1, 2, 3, 4};
|
||||
int b[] = {5, 6, 7, 8};
|
||||
|
||||
int iter_move_counter_one(0);
|
||||
int iter_move_counter_two(0);
|
||||
using View = IterMoveIterSwapTestRange<int*, /*IsSwappable=*/true, /*IsNoExcept=*/false>;
|
||||
using StrideView = std::ranges::stride_view<View>;
|
||||
auto svba = StrideView(View(a, a + 4, &iter_move_counter_one), 1).begin();
|
||||
auto svbb = StrideView(View(b, b + 4, &iter_move_counter_two), 1).begin();
|
||||
|
||||
static_assert(Swappable<std::ranges::iterator_t<StrideView>>);
|
||||
static_assert(!noexcept(std::ranges::iter_swap(svba, svbb)));
|
||||
|
||||
assert(a[0] == 1);
|
||||
assert(b[0] == 5);
|
||||
|
||||
std::ranges::iter_swap(svba, svbb);
|
||||
|
||||
assert(iter_move_counter_one == 1);
|
||||
assert(iter_move_counter_two == 1);
|
||||
assert(a[0] == 5);
|
||||
assert(b[0] == 1);
|
||||
}
|
||||
|
||||
{
|
||||
// iter_swap is not available when the base iterator is not indirectly_swappable.
|
||||
using View = IterMoveIterSwapTestRange<int*, /*IsSwappable=*/false, /*IsNoExcept=*/false>;
|
||||
using StrideView = std::ranges::stride_view<View>;
|
||||
|
||||
static_assert(!Swappable<std::ranges::iterator_t<StrideView>>);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 difference_type operator-(const iterator& x, const iterator& y)
|
||||
// friend constexpr difference_type operator-(default_sentinel_t, const iterator& x)
|
||||
// friend constexpr difference_type operator-(const iterator& x, default_sentinel_t)
|
||||
// friend constexpr iterator operator-(const iterator& i, difference_type s)
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
template <class T>
|
||||
concept CanMinus = std::is_same_v<typename T::difference_type, decltype(std::declval<T>() - std::declval<T>())> &&
|
||||
requires(T& t) { t - t; };
|
||||
|
||||
template <class T>
|
||||
concept CanSentinelMinus =
|
||||
std::is_same_v<typename T::difference_type, decltype(std::declval<T>() - std::default_sentinel)> &&
|
||||
std::is_same_v<typename T::difference_type, decltype(std::default_sentinel - std::declval<T>())> && requires(T& t) {
|
||||
t - std::default_sentinel;
|
||||
std::default_sentinel - t;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
concept CanDifferenceMinus = std::is_same_v<T, decltype(std::declval<T>() - 1)> && requires(T& t) { t - 1; };
|
||||
|
||||
// Input view: has sentinel minus but not iter-iter minus or difference minus.
|
||||
using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
|
||||
using StrideViewOverInputViewIter = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
|
||||
static_assert(!CanMinus<StrideViewOverInputViewIter>);
|
||||
static_assert(!CanDifferenceMinus<StrideViewOverInputViewIter>);
|
||||
static_assert(CanSentinelMinus<StrideViewOverInputViewIter>);
|
||||
|
||||
// Forward view: has sentinel minus but not iter-iter minus or difference minus.
|
||||
using ForwardView = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
|
||||
using StrideViewOverForwardViewIter = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
|
||||
static_assert(!CanMinus<StrideViewOverForwardViewIter>);
|
||||
static_assert(!CanDifferenceMinus<StrideViewOverForwardViewIter>);
|
||||
static_assert(CanSentinelMinus<StrideViewOverForwardViewIter>);
|
||||
|
||||
// Bidirectional view: has sentinel minus but not iter-iter minus or difference minus.
|
||||
using BidirView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
|
||||
using StrideViewOverBidirViewIter = std::ranges::iterator_t<std::ranges::stride_view<BidirView>>;
|
||||
static_assert(!CanMinus<StrideViewOverBidirViewIter>);
|
||||
static_assert(!CanDifferenceMinus<StrideViewOverBidirViewIter>);
|
||||
static_assert(CanSentinelMinus<StrideViewOverBidirViewIter>);
|
||||
|
||||
// Random access view: has iter-iter minus and difference minus, but no sentinel minus (non-sized sentinel).
|
||||
using RAView = BasicTestView<random_access_iterator<int*>>;
|
||||
using StrideViewOverRAViewIter = std::ranges::iterator_t<std::ranges::stride_view<RAView>>;
|
||||
static_assert(CanMinus<StrideViewOverRAViewIter>);
|
||||
static_assert(CanDifferenceMinus<StrideViewOverRAViewIter>);
|
||||
static_assert(!CanSentinelMinus<StrideViewOverRAViewIter>);
|
||||
|
||||
template <typename Iter>
|
||||
requires std::sized_sentinel_for<Iter, Iter> && (!std::forward_iterator<Iter>)
|
||||
constexpr bool test_non_forward_minus(Iter zero_begin, Iter one_begin, Iter end) {
|
||||
using Base = BasicTestView<Iter, Iter>;
|
||||
|
||||
auto base_zero = Base(zero_begin, end);
|
||||
auto base_one = Base(one_begin, end);
|
||||
auto sv_zero = std::ranges::stride_view(base_zero, 3);
|
||||
auto sv_one = std::ranges::stride_view(base_one, 3);
|
||||
|
||||
auto begin0 = sv_zero.begin();
|
||||
auto mid0 = begin0;
|
||||
++mid0; // stride 3 -> index 3
|
||||
auto far0 = mid0;
|
||||
++far0; // stride 3 -> index 6
|
||||
|
||||
auto begin1 = sv_one.begin();
|
||||
auto mid1 = begin1;
|
||||
++mid1; // stride 3 -> index 4
|
||||
|
||||
// Positive differences (uses ceil for non-forward).
|
||||
assert(mid0 - begin0 == 1);
|
||||
assert(far0 - begin0 == 2);
|
||||
assert(begin1 - begin0 == 1);
|
||||
assert(mid1 - begin0 == 2);
|
||||
|
||||
// Negative differences.
|
||||
assert(begin0 - mid0 == -1);
|
||||
assert(begin0 - far0 == -2);
|
||||
assert(begin0 - begin1 == -1);
|
||||
assert(begin0 - mid1 == -2);
|
||||
|
||||
// Sentinel minus.
|
||||
assert(std::default_sentinel - sv_zero.begin() == std::ranges::distance(sv_zero));
|
||||
assert(sv_zero.begin() - std::default_sentinel == -std::ranges::distance(sv_zero));
|
||||
assert(std::default_sentinel - sv_zero.end() == 0);
|
||||
assert(sv_zero.end() - std::default_sentinel == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <std::forward_iterator Iter>
|
||||
constexpr bool test_forward_minus(Iter begin, Iter end) {
|
||||
using Base = BasicTestView<Iter, Iter>;
|
||||
|
||||
auto base_zero = Base(begin, end);
|
||||
auto base_one = Base(begin + 1, end);
|
||||
auto sv_zero = std::ranges::stride_view(base_zero, 3);
|
||||
auto sv_one = std::ranges::stride_view(base_one, 3);
|
||||
|
||||
auto begin0 = sv_zero.begin();
|
||||
auto mid0 = begin0;
|
||||
++mid0; // stride 3 -> value 4
|
||||
auto far0 = mid0;
|
||||
++far0; // stride 3 -> value 7
|
||||
|
||||
auto begin1 = sv_one.begin(); // value 2
|
||||
auto mid1 = begin1;
|
||||
++mid1; // value 5
|
||||
|
||||
// Forward range uses exact division (no ceil).
|
||||
assert(mid0 - begin0 == 1);
|
||||
assert(far0 - begin0 == 2);
|
||||
assert(begin1 - begin0 == 0);
|
||||
assert(mid1 - begin0 == 1);
|
||||
|
||||
assert(begin0 - mid0 == -1);
|
||||
assert(begin0 - far0 == -2);
|
||||
|
||||
// Sentinel minus.
|
||||
assert(std::default_sentinel - sv_zero.begin() == std::ranges::distance(sv_zero));
|
||||
assert(sv_zero.begin() - std::default_sentinel == -std::ranges::distance(sv_zero));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
test_forward_minus(arr, arr + 11);
|
||||
|
||||
std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
test_forward_minus(vec.begin(), vec.end());
|
||||
}
|
||||
{
|
||||
// operator-(iterator, difference_type) -- only for random access ranges.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
|
||||
auto base = Base(arr, arr + 10);
|
||||
auto sv = std::ranges::stride_view(base, 3);
|
||||
|
||||
auto it = sv.begin();
|
||||
++it;
|
||||
++it;
|
||||
++it; // at index 9
|
||||
|
||||
auto it2 = it - 2; // back to index 3
|
||||
assert(*it2 == 4);
|
||||
auto it3 = it - 3; // back to index 0
|
||||
assert(*it3 == 1);
|
||||
}
|
||||
{
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
test_non_forward_minus(SizedInputIter(arr), SizedInputIter(arr + 1), SizedInputIter(arr + 10));
|
||||
}
|
||||
{
|
||||
// Test end - begin on the same view where size % stride != 0.
|
||||
// 10 elements, stride 3: strided elements at 0,3,6,9.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 10), 3);
|
||||
auto b = sv.begin();
|
||||
auto e = sv.end();
|
||||
assert(e - b == 4);
|
||||
assert(b - e == -4);
|
||||
assert(b - b == 0);
|
||||
assert(e - e == 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 n)
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
template <class T>
|
||||
concept CanMinusEqual = std::is_same_v<T&, decltype(std::declval<T>() -= 1)> && requires(T& t) { t -= 1; };
|
||||
|
||||
// Input view: no -=.
|
||||
using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
|
||||
using StrideViewOverInputViewIter = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
|
||||
static_assert(!CanMinusEqual<StrideViewOverInputViewIter>);
|
||||
|
||||
// Forward view: no -=.
|
||||
using ForwardView = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
|
||||
using StrideViewOverForwardViewIter = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
|
||||
static_assert(!CanMinusEqual<StrideViewOverForwardViewIter>);
|
||||
|
||||
// Bidirectional view: no -=.
|
||||
using BidirView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
|
||||
using StrideViewOverBidirViewIter = std::ranges::iterator_t<std::ranges::stride_view<BidirView>>;
|
||||
static_assert(!CanMinusEqual<StrideViewOverBidirViewIter>);
|
||||
|
||||
// Random access view: has -=.
|
||||
using RAView = BasicTestView<random_access_iterator<int*>>;
|
||||
using StrideViewOverRAViewIter = std::ranges::iterator_t<std::ranges::stride_view<RAView>>;
|
||||
static_assert(CanMinusEqual<StrideViewOverRAViewIter>);
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// Basic -= test with stride 1.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 10), 1);
|
||||
auto it = sv.begin();
|
||||
it += 5;
|
||||
assert(*it == 6);
|
||||
it -= 3;
|
||||
assert(*it == 3);
|
||||
it -= 2;
|
||||
assert(*it == 1);
|
||||
}
|
||||
{
|
||||
// -= test with stride 3.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 10), 3);
|
||||
auto it = sv.begin();
|
||||
it += 3; // at index 9 (value 10)
|
||||
assert(*it == 10);
|
||||
it -= 1; // at index 6 (value 7)
|
||||
assert(*it == 7);
|
||||
it -= 2; // at index 0 (value 1)
|
||||
assert(*it == 1);
|
||||
}
|
||||
{
|
||||
// -= when the stride doesn't evenly divide the range: stride past the end, then back.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view<Base>(Base(arr, arr + 10), 7);
|
||||
auto it = sv.end();
|
||||
it -= 1; // back to last strided element (value 8)
|
||||
assert(*it == 8);
|
||||
it -= 1; // back to first element (value 1)
|
||||
assert(*it == 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// constexpr iterator operator+(difference_type n, const iterator& i)
|
||||
// constexpr iterator operator+(const iterator& i, difference_type n)
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
template <class T>
|
||||
concept CanPlus =
|
||||
std::is_same_v<T, decltype(std::declval<T>() + std::declval<typename T::difference_type>())> &&
|
||||
std::is_same_v<T, decltype(std::declval<typename T::difference_type>() + std::declval<T>())> &&
|
||||
requires(T& t, typename T::difference_type u) { t = t + u; } &&
|
||||
requires(T& t, typename T::difference_type u) { t = u + t; };
|
||||
|
||||
// Make sure that we cannot use + on a stride view iterator and difference_type
|
||||
// over an input view.(sized sentinel)
|
||||
using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
|
||||
using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
|
||||
|
||||
static_assert(std::ranges::input_range<InputView>);
|
||||
static_assert(!CanPlus<StrideViewOverInputViewIterator>);
|
||||
|
||||
// Make sure that we cannot use + on a stride view iterator and difference_type
|
||||
// over a forward view.(sized sentinel)
|
||||
using ForwardView = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
|
||||
using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
|
||||
|
||||
static_assert(std::ranges::forward_range<ForwardView>);
|
||||
static_assert(!CanPlus<StrideViewOverForwardViewIterator>);
|
||||
|
||||
// Make sure that we cannot use + on a stride view iterator and difference_type
|
||||
// over a bidirectional view. (sized sentinel)
|
||||
using BidirectionalView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
|
||||
using StrideViewOverBidirectionalViewIterator = std::ranges::iterator_t<std::ranges::stride_view<BidirectionalView>>;
|
||||
|
||||
static_assert(std::ranges::bidirectional_range<BidirectionalView>);
|
||||
static_assert(!CanPlus<StrideViewOverBidirectionalViewIterator>);
|
||||
|
||||
// Make sure that we can use += on a stride view iterator and difference_type
|
||||
// over a random access view. (non sized sentinel)
|
||||
template <typename RandomAccessIterator = random_access_iterator<int*>>
|
||||
using RandomAccessView = BasicTestView<RandomAccessIterator>;
|
||||
using StrideViewOverRandomAccessViewIterator = std::ranges::iterator_t<std::ranges::stride_view<RandomAccessView<>>>;
|
||||
|
||||
static_assert(std::ranges::random_access_range<RandomAccessView<>>);
|
||||
static_assert(CanPlus<StrideViewOverRandomAccessViewIterator>);
|
||||
|
||||
constexpr bool test() {
|
||||
std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
|
||||
auto begin = vec.begin();
|
||||
auto end = vec.end();
|
||||
auto distance = 4;
|
||||
|
||||
using Base = RandomAccessView<std::vector<int>::iterator>;
|
||||
static_assert(std::ranges::random_access_range<Base>);
|
||||
|
||||
{
|
||||
// iterator + distance produces the same element as starting at begin + distance.
|
||||
auto base_view = Base(begin, end);
|
||||
auto stride_view_over_base_view = std::ranges::stride_view(base_view, 1);
|
||||
|
||||
auto base_view_offset = Base(begin + distance, end);
|
||||
auto stride_view_over_base_view_offset = std::ranges::stride_view(base_view_offset, 1);
|
||||
|
||||
assert(*(stride_view_over_base_view.begin() + distance) == *(stride_view_over_base_view_offset.begin()));
|
||||
}
|
||||
{
|
||||
// iterator + 1 with a large stride reaches the same element as iterator + stride with stride 1.
|
||||
auto base_view = Base(begin, end);
|
||||
auto stride_view_over_base_view = std::ranges::stride_view(base_view, 1);
|
||||
auto distance_to_last = (end - 1) - begin;
|
||||
auto stride_view_over_base_view_big_step = std::ranges::stride_view(base_view, distance_to_last);
|
||||
|
||||
assert(*(stride_view_over_base_view_big_step.begin() + 1) ==
|
||||
*(stride_view_over_base_view.begin() + distance_to_last));
|
||||
// iterator + 2 past the end of a large-stride view equals the end of the stride-1 view.
|
||||
assert((stride_view_over_base_view_big_step.begin() + 2) == (stride_view_over_base_view.end()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 n)
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
template <class T>
|
||||
concept CanPlus = std::is_same_v<T&, decltype(std::declval<T>() += std::declval<typename T::difference_type>())> &&
|
||||
requires(T& t, typename T::difference_type u) { t += u; };
|
||||
|
||||
// Make sure that we cannot use += on a stride view iterator
|
||||
// over an input view.(sized sentinel)
|
||||
using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
|
||||
using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
|
||||
|
||||
static_assert(std::ranges::input_range<InputView>);
|
||||
static_assert(!CanPlus<StrideViewOverInputViewIterator>);
|
||||
|
||||
// Make sure that we cannot use += on a stride view iterator
|
||||
// over a forward view.(sized sentinel)
|
||||
using ForwardView = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
|
||||
using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
|
||||
|
||||
static_assert(std::ranges::forward_range<ForwardView>);
|
||||
static_assert(!CanPlus<StrideViewOverForwardViewIterator>);
|
||||
|
||||
// Make sure that we cannot use += on a stride view iterator
|
||||
// over a bidirectional view. (sized sentinel)
|
||||
using BidirectionalView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
|
||||
using StrideViewOverBidirectionalViewIterator = std::ranges::iterator_t<std::ranges::stride_view<BidirectionalView>>;
|
||||
|
||||
static_assert(std::ranges::bidirectional_range<BidirectionalView>);
|
||||
static_assert(!CanPlus<StrideViewOverBidirectionalViewIterator>);
|
||||
|
||||
// Make sure that we can use += on a stride view iterator
|
||||
// over a random access view. (non sized sentinel)
|
||||
template <typename RandomAccessIterator = random_access_iterator<int*>>
|
||||
using RandomAccessView = BasicTestView<RandomAccessIterator>;
|
||||
using StrideViewOverRandomAccessViewIterator = std::ranges::iterator_t<std::ranges::stride_view<RandomAccessView<>>>;
|
||||
|
||||
static_assert(std::ranges::random_access_range<RandomAccessView<>>);
|
||||
static_assert(CanPlus<StrideViewOverRandomAccessViewIterator>);
|
||||
|
||||
constexpr bool test() {
|
||||
std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
|
||||
using Iter = std::vector<int>::iterator;
|
||||
|
||||
auto begin = vec.begin();
|
||||
auto end = vec.end();
|
||||
|
||||
using Base = RandomAccessView<Iter>;
|
||||
static_assert(std::ranges::random_access_range<Base>);
|
||||
auto base = Base(begin, end);
|
||||
|
||||
// += with stride 1: advancing by distance matches starting at begin + distance.
|
||||
{
|
||||
auto sv = std::ranges::stride_view(base, 1);
|
||||
auto it = sv.begin();
|
||||
auto& result = (it += 4);
|
||||
assert(&result == &it);
|
||||
|
||||
auto it2 = std::ranges::stride_view(Base(begin + 4, end), 1).begin();
|
||||
assert(*it == *it2);
|
||||
}
|
||||
|
||||
// += past the end, then -= back: the remainder is handled correctly.
|
||||
{
|
||||
auto sv = std::ranges::stride_view(base, (end - begin) - 1);
|
||||
auto it = sv.begin();
|
||||
|
||||
// This += should move us into a position where the stride doesn't evenly divide the range.
|
||||
// Do a -= 1 here to confirm that the remainder is taken into account.
|
||||
it += 2;
|
||||
it -= 1;
|
||||
assert(*it == *(sv.begin() + 1));
|
||||
}
|
||||
|
||||
// += 0 is a no-op.
|
||||
{
|
||||
auto sv = std::ranges::stride_view(base, 3);
|
||||
auto it = sv.begin();
|
||||
it += 1; // at index 3
|
||||
assert(*it == *(begin + 3));
|
||||
it += 0;
|
||||
assert(*it == *(begin + 3));
|
||||
}
|
||||
|
||||
// += with negative n.
|
||||
{
|
||||
auto sv = std::ranges::stride_view(base, 3);
|
||||
auto it = sv.begin();
|
||||
it += 3; // at index 9
|
||||
assert(*it == *(begin + 9));
|
||||
it += -2; // back to index 3
|
||||
assert(*it == *(begin + 3));
|
||||
it += -1; // back to index 0
|
||||
assert(*it == *begin);
|
||||
}
|
||||
|
||||
// += negative from end.
|
||||
{
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
using CommonBase = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(CommonBase(arr, arr + 11), 3);
|
||||
auto it = sv.end();
|
||||
it += -1; // last strided element (index 9)
|
||||
assert(*it == 10);
|
||||
it += -3; // back to begin (index 0)
|
||||
assert(*it == 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
// constexpr decltype(auto) operator[](difference_type n) const
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
|
||||
#include "../types.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
template <class T>
|
||||
concept CanSubscript = requires(T& t) { t[0]; };
|
||||
|
||||
// Input view: no subscript.
|
||||
using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
|
||||
using StrideInputIter = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
|
||||
static_assert(!CanSubscript<StrideInputIter>);
|
||||
|
||||
// Forward view: no subscript.
|
||||
using FwdView = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
|
||||
using StrideFwdIter = std::ranges::iterator_t<std::ranges::stride_view<FwdView>>;
|
||||
static_assert(!CanSubscript<StrideFwdIter>);
|
||||
|
||||
// Bidirectional view: no subscript.
|
||||
using BidirView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
|
||||
using StrideBidirIter = std::ranges::iterator_t<std::ranges::stride_view<BidirView>>;
|
||||
static_assert(!CanSubscript<StrideBidirIter>);
|
||||
|
||||
// Random access view: subscript available.
|
||||
using RAView = BasicTestView<random_access_iterator<int*>>;
|
||||
using StrideRAIter = std::ranges::iterator_t<std::ranges::stride_view<RAView>>;
|
||||
static_assert(CanSubscript<StrideRAIter>);
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// Subscript with stride 1.
|
||||
int arr[] = {10, 20, 30, 40, 50};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 5), 1);
|
||||
auto it = sv.begin();
|
||||
|
||||
assert(it[0] == 10);
|
||||
assert(it[1] == 20);
|
||||
assert(it[2] == 30);
|
||||
assert(it[3] == 40);
|
||||
assert(it[4] == 50);
|
||||
}
|
||||
{
|
||||
// Subscript with stride 2.
|
||||
int arr[] = {10, 20, 30, 40, 50};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 5), 2);
|
||||
auto it = sv.begin();
|
||||
|
||||
assert(it[0] == 10);
|
||||
assert(it[1] == 30);
|
||||
assert(it[2] == 50);
|
||||
}
|
||||
{
|
||||
// Subscript with stride 3.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 10), 3);
|
||||
auto it = sv.begin();
|
||||
|
||||
assert(it[0] == 1);
|
||||
assert(it[1] == 4);
|
||||
assert(it[2] == 7);
|
||||
assert(it[3] == 10);
|
||||
}
|
||||
{
|
||||
// Subscript from a non-begin position.
|
||||
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 10), 3);
|
||||
auto it = sv.begin();
|
||||
++it; // now at index 3 (value 4)
|
||||
|
||||
assert(it[0] == 4);
|
||||
assert(it[1] == 7);
|
||||
assert(it[2] == 10);
|
||||
assert(it[-1] == 1);
|
||||
}
|
||||
{
|
||||
// Verify return type is a reference.
|
||||
int arr[] = {1, 2, 3};
|
||||
using Base = BasicTestView<int*, int*>;
|
||||
auto sv = std::ranges::stride_view(Base(arr, arr + 3), 1);
|
||||
auto it = sv.begin();
|
||||
static_assert(std::is_same_v<decltype(it[0]), int&>);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
|
||||
// stride_view::iterator::difference_type
|
||||
// stride_view::iterator::value_type
|
||||
// stride_view::iterator::iterator_concept
|
||||
// stride_view::iterator::iterator_category
|
||||
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "../types.h"
|
||||
|
||||
template <class T>
|
||||
concept HasIteratorCategory = requires { typename T::iterator_category; };
|
||||
|
||||
template <class Iterator>
|
||||
using StrideViewFor = std::ranges::stride_view<BasicTestView<Iterator, sentinel_wrapper<Iterator>>>;
|
||||
|
||||
template <class Iterator>
|
||||
using StrideIteratorFor = std::ranges::iterator_t<StrideViewFor<Iterator>>;
|
||||
|
||||
struct ForwardIteratorWithInputCategory {
|
||||
using difference_type = int;
|
||||
using value_type = int;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
ForwardIteratorWithInputCategory();
|
||||
ForwardIteratorWithInputCategory& operator++();
|
||||
ForwardIteratorWithInputCategory operator++(int);
|
||||
int& operator*() const;
|
||||
friend bool operator==(ForwardIteratorWithInputCategory, ForwardIteratorWithInputCategory);
|
||||
};
|
||||
static_assert(std::forward_iterator<ForwardIteratorWithInputCategory>);
|
||||
|
||||
// Non-simple view: forward when non-const, raw pointer when const.
|
||||
// This exposes the bug where iterator_category is always derived from
|
||||
// the non-const view's iterator instead of maybe-const<Const, V>.
|
||||
struct DifferentCategoryView : std::ranges::view_base {
|
||||
forward_iterator<int*> begin();
|
||||
forward_iterator<int*> end();
|
||||
const int* begin() const;
|
||||
const int* end() const;
|
||||
};
|
||||
|
||||
// Non-simple view: input-only when non-const, forward when const.
|
||||
// Tests that iterator_category is absent for the non-const iterator
|
||||
// but present for the const iterator.
|
||||
struct ForwardWhenConstView : std::ranges::view_base {
|
||||
cpp17_input_iterator<int*> begin();
|
||||
sentinel_wrapper<cpp17_input_iterator<int*>> end();
|
||||
forward_iterator<const int*> begin() const;
|
||||
forward_iterator<const int*> end() const;
|
||||
};
|
||||
|
||||
void f() {
|
||||
// Check that value_type is range_value_t and difference_type is range_difference_t
|
||||
{
|
||||
auto check = []<class Iterator> {
|
||||
using StrideView = StrideViewFor<Iterator>;
|
||||
using StrideIterator = StrideIteratorFor<Iterator>;
|
||||
static_assert(std::is_same_v<typename StrideIterator::value_type, std::ranges::range_value_t<StrideView>>);
|
||||
static_assert(
|
||||
std::is_same_v<typename StrideIterator::difference_type, std::ranges::range_difference_t<StrideView>>);
|
||||
};
|
||||
check.operator()<cpp17_input_iterator<int*>>();
|
||||
check.operator()<forward_iterator<int*>>();
|
||||
check.operator()<bidirectional_iterator<int*>>();
|
||||
check.operator()<random_access_iterator<int*>>();
|
||||
check.operator()<contiguous_iterator<int*>>();
|
||||
check.operator()<int*>();
|
||||
}
|
||||
|
||||
// Check iterator_concept for various categories of ranges
|
||||
{
|
||||
static_assert(
|
||||
std::is_same_v<StrideIteratorFor<cpp17_input_iterator<int*>>::iterator_concept, std::input_iterator_tag>);
|
||||
static_assert(
|
||||
std::is_same_v<StrideIteratorFor<forward_iterator<int*>>::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<StrideIteratorFor<ForwardIteratorWithInputCategory>::iterator_concept,
|
||||
std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<StrideIteratorFor<bidirectional_iterator<int*>>::iterator_concept,
|
||||
std::bidirectional_iterator_tag>);
|
||||
static_assert(std::is_same_v<StrideIteratorFor<random_access_iterator<int*>>::iterator_concept,
|
||||
std::random_access_iterator_tag>);
|
||||
static_assert(std::is_same_v<StrideIteratorFor<contiguous_iterator<int*>>::iterator_concept,
|
||||
std::random_access_iterator_tag>);
|
||||
static_assert(std::is_same_v<StrideIteratorFor<int*>::iterator_concept, std::random_access_iterator_tag>);
|
||||
}
|
||||
|
||||
// Check iterator_category for various categories of ranges
|
||||
{
|
||||
static_assert(!HasIteratorCategory<StrideIteratorFor<cpp17_input_iterator<int*>>>);
|
||||
static_assert(
|
||||
std::is_same_v<StrideIteratorFor<forward_iterator<int*>>::iterator_category, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<StrideIteratorFor<ForwardIteratorWithInputCategory>::iterator_category,
|
||||
std::input_iterator_tag>);
|
||||
static_assert(std::is_same_v<StrideIteratorFor<bidirectional_iterator<int*>>::iterator_category,
|
||||
std::bidirectional_iterator_tag>);
|
||||
static_assert(std::is_same_v<StrideIteratorFor<random_access_iterator<int*>>::iterator_category,
|
||||
std::random_access_iterator_tag>);
|
||||
static_assert(std::is_same_v<StrideIteratorFor<contiguous_iterator<int*>>::iterator_category,
|
||||
std::random_access_iterator_tag>);
|
||||
static_assert(std::is_same_v<StrideIteratorFor<int*>::iterator_category, std::random_access_iterator_tag>);
|
||||
}
|
||||
|
||||
// Check that const vs non-const iterators get the correct iterator_category
|
||||
// when the view has different iterator categories for const and non-const.
|
||||
{
|
||||
using SV = std::ranges::stride_view<DifferentCategoryView>;
|
||||
using NonConstIter = std::ranges::iterator_t<SV>;
|
||||
using ConstIter = std::ranges::iterator_t<const SV>;
|
||||
|
||||
static_assert(std::is_same_v<NonConstIter::iterator_concept, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<ConstIter::iterator_concept, std::random_access_iterator_tag>);
|
||||
|
||||
static_assert(std::is_same_v<NonConstIter::iterator_category, std::forward_iterator_tag>);
|
||||
static_assert(std::is_same_v<ConstIter::iterator_category, std::random_access_iterator_tag>);
|
||||
}
|
||||
|
||||
// Check that iterator_category presence/absence depends on the correct
|
||||
// const-qualified Base, not always the non-const view.
|
||||
{
|
||||
using SV = std::ranges::stride_view<ForwardWhenConstView>;
|
||||
using NonConstIter = std::ranges::iterator_t<SV>;
|
||||
using ConstIter = std::ranges::iterator_t<const SV>;
|
||||
|
||||
static_assert(!HasIteratorCategory<NonConstIter>);
|
||||
static_assert(HasIteratorCategory<ConstIter>);
|
||||
static_assert(std::is_same_v<ConstIter::iterator_category, std::forward_iterator_tag>);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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<V>
|
||||
// constexpr auto size() const requires sized_range<const V>
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "types.h"
|
||||
|
||||
// There is no size member function on a stride view over a view that
|
||||
// is *not* a sized range
|
||||
static_assert(!std::ranges::sized_range<BasicTestView<cpp17_input_iterator<int*>>>);
|
||||
static_assert(!std::ranges::sized_range<std::ranges::stride_view<BasicTestView<cpp17_input_iterator<int*>>>>);
|
||||
|
||||
// There is a size member function on a stride view over a view that
|
||||
// *is* a sized range
|
||||
static_assert(std::ranges::sized_range<BasicTestView<int*, sentinel_wrapper<int*>, /*IsSized=*/true>>);
|
||||
static_assert(
|
||||
std::ranges::sized_range<std::ranges::stride_view<BasicTestView<int*, sentinel_wrapper<int*>, /*IsSized=*/true>>>);
|
||||
|
||||
constexpr bool test() {
|
||||
{
|
||||
// Test with stride as exact multiple of number of elements in view strided over.
|
||||
auto iota = std::views::iota(0, 12);
|
||||
static_assert(std::ranges::sized_range<decltype(iota)>);
|
||||
auto strided = std::views::stride(iota, 3);
|
||||
static_assert(std::ranges::sized_range<decltype(strided)>);
|
||||
assert(strided.size() == 4);
|
||||
}
|
||||
|
||||
{
|
||||
// Test with stride as inexact multiple of number of elements in view strided over.
|
||||
auto iota = std::views::iota(0, 22);
|
||||
static_assert(std::ranges::sized_range<decltype(iota)>);
|
||||
auto strided = std::views::stride(iota, 3);
|
||||
static_assert(std::ranges::sized_range<decltype(strided)>);
|
||||
assert(strided.size() == 8);
|
||||
}
|
||||
{
|
||||
// Empty range.
|
||||
auto strided = std::views::iota(0, 0) | std::views::stride(3);
|
||||
assert(strided.size() == 0);
|
||||
}
|
||||
{
|
||||
// Stride larger than range size.
|
||||
auto strided = std::views::iota(0, 3) | std::views::stride(10);
|
||||
assert(strided.size() == 1);
|
||||
}
|
||||
{
|
||||
// Stride equal to range size.
|
||||
auto strided = std::views::iota(0, 5) | std::views::stride(5);
|
||||
assert(strided.size() == 1);
|
||||
}
|
||||
{
|
||||
// Stride of 1.
|
||||
auto strided = std::views::iota(0, 7) | std::views::stride(1);
|
||||
assert(strided.size() == 7);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 range_difference_t<V> stride() const noexcept;
|
||||
|
||||
#include <cassert>
|
||||
#include <ranges>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
#include "types.h"
|
||||
|
||||
constexpr bool test() {
|
||||
using View = BasicTestView<cpp17_input_iterator<int*>>;
|
||||
int arr[] = {1, 2, 3};
|
||||
View view(cpp17_input_iterator<int*>(arr), cpp17_input_iterator<int*>(arr + 3));
|
||||
|
||||
const std::ranges::stride_view<View> strided(view, 2);
|
||||
static_assert(noexcept(strided.stride()));
|
||||
ASSERT_SAME_TYPE(std::ranges::range_difference_t<View>, decltype(strided.stride()));
|
||||
assert(strided.stride() == 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
290
libcxx/test/std/ranges/range.adaptors/range.stride.view/types.h
Normal file
290
libcxx/test/std/ranges/range.adaptors/range.stride.view/types.h
Normal file
@@ -0,0 +1,290 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_STRIDE_TYPES_H
|
||||
#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H
|
||||
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include "test_iterators.h"
|
||||
#include "test_range.h"
|
||||
|
||||
// Concepts
|
||||
|
||||
template <typename Iter>
|
||||
concept IterDifferable = std::invocable<std::minus<>, Iter, Iter>;
|
||||
|
||||
// Iterators
|
||||
|
||||
// The base for an iterator that keeps a count of the times that it is
|
||||
// moved and copied.
|
||||
template <class Derived, std::input_iterator Iter>
|
||||
struct IterBase {
|
||||
using value_type = typename std::iterator_traits<Iter>::value_type;
|
||||
using difference_type = typename std::iterator_traits<Iter>::difference_type;
|
||||
|
||||
int* move_counter = nullptr;
|
||||
int* copy_counter = nullptr;
|
||||
|
||||
Iter value_{};
|
||||
|
||||
constexpr IterBase() = default;
|
||||
constexpr explicit IterBase(Iter value) : value_(value) {}
|
||||
|
||||
constexpr IterBase(const IterBase& other) noexcept {
|
||||
copy_counter = other.copy_counter;
|
||||
move_counter = other.move_counter;
|
||||
if (copy_counter != nullptr) {
|
||||
(*copy_counter)++;
|
||||
}
|
||||
value_ = other.value_;
|
||||
}
|
||||
|
||||
constexpr IterBase(IterBase&& other) noexcept {
|
||||
copy_counter = other.copy_counter;
|
||||
move_counter = other.move_counter;
|
||||
if (move_counter != nullptr) {
|
||||
(*move_counter)++;
|
||||
}
|
||||
value_ = std::move(other.value_);
|
||||
}
|
||||
constexpr IterBase& operator=(const IterBase& other) = default;
|
||||
constexpr IterBase& operator=(IterBase&& other) = default;
|
||||
};
|
||||
|
||||
// The base for an input iterator that keeps a count of the times that it is
|
||||
// moved and copied.
|
||||
template <class Derived, std::input_iterator Iter = int*, bool IsSized = false>
|
||||
requires((!IsSized) || (IsSized && IterDifferable<Iter>))
|
||||
struct InputIter : IterBase<Derived, Iter> {
|
||||
using Base = IterBase<Derived, Iter>;
|
||||
|
||||
using typename Base::difference_type;
|
||||
using typename Base::value_type;
|
||||
|
||||
using iterator_concept = std::input_iterator_tag;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
using Base::Base;
|
||||
|
||||
constexpr value_type operator*() const { return *Base::value_; }
|
||||
constexpr Derived& operator++() {
|
||||
Base::value_++;
|
||||
return static_cast<Derived&>(*this);
|
||||
}
|
||||
constexpr Derived operator++(int) {
|
||||
auto nv = *this;
|
||||
Base::value_++;
|
||||
return nv;
|
||||
}
|
||||
friend constexpr bool operator==(const Derived& left, const Derived& right) { return left.value_ == right.value_; }
|
||||
friend constexpr difference_type operator-(const Derived& left, const Derived& right)
|
||||
requires IsSized
|
||||
{
|
||||
return left.value_ - right.value_;
|
||||
}
|
||||
};
|
||||
|
||||
// In input iterator that is sized.
|
||||
struct SizedInputIter : InputIter<SizedInputIter, int*, true> {
|
||||
using InputIter::InputIter;
|
||||
};
|
||||
static_assert(std::input_iterator<SizedInputIter>);
|
||||
static_assert(std::sized_sentinel_for<SizedInputIter, SizedInputIter>);
|
||||
|
||||
// Views
|
||||
|
||||
// Put IterMoveIterSwapTestRangeIterator in a namespace to test ADL of CPOs iter_swap and iter_move
|
||||
// (see iter_swap.pass.cpp and iter_move.pass.cpp).
|
||||
namespace adl {
|
||||
template <std::input_iterator Iter = int*, bool IsIterSwappable = true, bool IsNoExceptIterMoveable = true>
|
||||
struct IterMoveIterSwapTestRangeIterator
|
||||
: InputIter<IterMoveIterSwapTestRangeIterator<Iter, IsIterSwappable, IsNoExceptIterMoveable>, Iter, false> {
|
||||
int* counter_{nullptr};
|
||||
|
||||
using InputIter<IterMoveIterSwapTestRangeIterator<Iter, IsIterSwappable, IsNoExceptIterMoveable>, Iter, false>::
|
||||
InputIter;
|
||||
|
||||
constexpr IterMoveIterSwapTestRangeIterator(Iter value, int* counter)
|
||||
: InputIter<IterMoveIterSwapTestRangeIterator<Iter, IsIterSwappable, IsNoExceptIterMoveable>, Iter, false>(value),
|
||||
counter_(counter) {}
|
||||
|
||||
friend constexpr void iter_swap(IterMoveIterSwapTestRangeIterator t, IterMoveIterSwapTestRangeIterator u) noexcept
|
||||
requires IsIterSwappable && IsNoExceptIterMoveable
|
||||
{
|
||||
(*t.counter_)++;
|
||||
(*u.counter_)++;
|
||||
std::swap(*t.value_, *u.value_);
|
||||
}
|
||||
|
||||
friend constexpr void iter_swap(IterMoveIterSwapTestRangeIterator t, IterMoveIterSwapTestRangeIterator u)
|
||||
requires IsIterSwappable && (!IsNoExceptIterMoveable)
|
||||
{
|
||||
(*t.counter_)++;
|
||||
(*u.counter_)++;
|
||||
std::swap(*t.value_, *u.value_);
|
||||
}
|
||||
|
||||
friend constexpr auto iter_move(const IterMoveIterSwapTestRangeIterator& t)
|
||||
requires(!IsNoExceptIterMoveable)
|
||||
{
|
||||
(*t.counter_)++;
|
||||
return *t.value_;
|
||||
}
|
||||
friend constexpr auto iter_move(const IterMoveIterSwapTestRangeIterator& t) noexcept
|
||||
requires IsNoExceptIterMoveable
|
||||
{
|
||||
(*t.counter_)++;
|
||||
return *t.value_;
|
||||
}
|
||||
};
|
||||
} // namespace adl
|
||||
|
||||
template <typename Iter = int*, bool IsSwappable = true, bool IsNoExcept = true>
|
||||
struct IterMoveIterSwapTestRange : std::ranges::view_base {
|
||||
adl::IterMoveIterSwapTestRangeIterator<Iter, IsSwappable, IsNoExcept> begin_;
|
||||
adl::IterMoveIterSwapTestRangeIterator<Iter, IsSwappable, IsNoExcept> end_;
|
||||
constexpr IterMoveIterSwapTestRange(const Iter& begin, const Iter& end, int* counter)
|
||||
: begin_(adl::IterMoveIterSwapTestRangeIterator<Iter, IsSwappable, IsNoExcept>(begin, counter)),
|
||||
end_(adl::IterMoveIterSwapTestRangeIterator<Iter, IsSwappable, IsNoExcept>(end, counter)) {}
|
||||
constexpr adl::IterMoveIterSwapTestRangeIterator<Iter, IsSwappable, IsNoExcept> begin() const { return begin_; }
|
||||
constexpr adl::IterMoveIterSwapTestRangeIterator<Iter, IsSwappable, IsNoExcept> end() const { return end_; }
|
||||
};
|
||||
|
||||
// Views
|
||||
|
||||
// Depending upon configuration, ViewOrRange is either a View or not.
|
||||
template <bool IsView>
|
||||
struct MaybeView {};
|
||||
template <>
|
||||
struct MaybeView<true> : std::ranges::view_base {};
|
||||
|
||||
template <std::input_iterator Iter,
|
||||
std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>,
|
||||
bool IsSized = false,
|
||||
bool IsView = false,
|
||||
bool IsCopyable = false >
|
||||
requires((!IsSized) || (IsSized && IterDifferable<Iter>))
|
||||
struct BasicTestViewOrRange : MaybeView<IsView> {
|
||||
Iter begin_{};
|
||||
Iter end_{};
|
||||
|
||||
constexpr BasicTestViewOrRange(const Iter& b, const Iter& e) : begin_(b), end_(e) {}
|
||||
|
||||
constexpr Iter begin() { return begin_; }
|
||||
constexpr Iter begin() const { return begin_; }
|
||||
constexpr Sent end() { return Sent{end_}; }
|
||||
constexpr Sent end() const { return Sent{end_}; }
|
||||
|
||||
constexpr auto size() const
|
||||
requires IsSized
|
||||
{
|
||||
return begin_ - end_;
|
||||
}
|
||||
|
||||
constexpr BasicTestViewOrRange(BasicTestViewOrRange&& other) = default;
|
||||
constexpr BasicTestViewOrRange& operator=(BasicTestViewOrRange&&) = default;
|
||||
|
||||
constexpr BasicTestViewOrRange(const BasicTestViewOrRange&)
|
||||
requires(!IsCopyable)
|
||||
= delete;
|
||||
constexpr BasicTestViewOrRange(const BasicTestViewOrRange&)
|
||||
requires IsCopyable
|
||||
= default;
|
||||
|
||||
constexpr BasicTestViewOrRange& operator=(const BasicTestViewOrRange&)
|
||||
requires(!IsCopyable)
|
||||
= delete;
|
||||
constexpr BasicTestViewOrRange& operator=(const BasicTestViewOrRange&)
|
||||
requires IsCopyable
|
||||
= default;
|
||||
};
|
||||
|
||||
template <std::input_iterator Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>, bool IsSized = false>
|
||||
requires((!IsSized) || (IsSized && IterDifferable<Iter>))
|
||||
using BasicTestView = BasicTestViewOrRange<Iter, Sent, IsSized, true /* IsView */, true /* IsCopyable */>;
|
||||
|
||||
template <std::input_iterator Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>, bool IsCopyable = true>
|
||||
using MaybeCopyableAlwaysMoveableView = BasicTestViewOrRange<Iter, Sent, false, true, IsCopyable>;
|
||||
|
||||
static_assert(std::ranges::view<MaybeCopyableAlwaysMoveableView<cpp17_input_iterator<int*>>>);
|
||||
static_assert(std::ranges::view<MaybeCopyableAlwaysMoveableView<cpp17_input_iterator<int*>,
|
||||
sentinel_wrapper<cpp17_input_iterator<int*>>,
|
||||
false>>);
|
||||
|
||||
static_assert(std::copyable<MaybeCopyableAlwaysMoveableView<cpp17_input_iterator<int*>>>);
|
||||
template <std::input_iterator Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>>
|
||||
using CopyableView = MaybeCopyableAlwaysMoveableView<Iter, Sent>;
|
||||
static_assert(std::copyable<CopyableView<cpp17_input_iterator<int*>>>);
|
||||
|
||||
template <class Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>>
|
||||
using MoveOnlyView = MaybeCopyableAlwaysMoveableView<Iter, Sent, false>;
|
||||
static_assert(!std::copyable<MoveOnlyView<cpp17_input_iterator<int*>>>);
|
||||
|
||||
template <bool IsSimple, bool IsConst = IsSimple, bool IsCommon = true, bool IsSized = false>
|
||||
struct MaybeConstCommonSimpleView : std::ranges::view_base {
|
||||
int* begin();
|
||||
int* begin() const
|
||||
requires(IsConst && IsSimple);
|
||||
double* begin() const
|
||||
requires(IsConst && !IsSimple);
|
||||
|
||||
int* end()
|
||||
requires(IsCommon);
|
||||
void* end()
|
||||
requires(!IsCommon);
|
||||
|
||||
int* end() const
|
||||
requires(IsConst && IsCommon && IsSimple);
|
||||
double* end() const
|
||||
requires(IsConst && IsCommon && !IsSimple);
|
||||
|
||||
void* end() const
|
||||
requires(IsConst && !IsCommon);
|
||||
|
||||
size_t size() const
|
||||
requires(IsSized);
|
||||
};
|
||||
|
||||
using UnSimpleNoConstCommonView = MaybeConstCommonSimpleView<false, false, true>;
|
||||
using UnSimpleConstView = MaybeConstCommonSimpleView<false, true, true>;
|
||||
using UnsimpleUnCommonConstView = MaybeConstCommonSimpleView<false, true, false>;
|
||||
using SimpleUnCommonConstView = MaybeConstCommonSimpleView<true, true, false>;
|
||||
using SimpleCommonConstView = MaybeConstCommonSimpleView<true, true, true>;
|
||||
|
||||
// Don't move/hold the iterator itself, copy/hold the base
|
||||
// of that iterator and reconstruct the iterator on demand.
|
||||
// May result in aliasing (if, e.g., Iterator is an iterator
|
||||
// over int *).
|
||||
template <class Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>>
|
||||
struct ViewOverNonCopyableIterator : std::ranges::view_base {
|
||||
constexpr explicit ViewOverNonCopyableIterator(Iter it, Sent sent) : it_(base(it)), sent_(base(sent)) {}
|
||||
|
||||
ViewOverNonCopyableIterator(ViewOverNonCopyableIterator&&) = default;
|
||||
ViewOverNonCopyableIterator& operator=(ViewOverNonCopyableIterator&&) = default;
|
||||
|
||||
constexpr Iter begin() const { return Iter(it_); }
|
||||
constexpr Sent end() const { return Sent(sent_); }
|
||||
|
||||
private:
|
||||
decltype(base(std::declval<Iter>())) it_;
|
||||
decltype(base(std::declval<Sent>())) sent_;
|
||||
};
|
||||
|
||||
// Ranges
|
||||
|
||||
template <std::input_iterator Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>, bool IsSized = false>
|
||||
requires((!IsSized) || (IsSized && IterDifferable<Iter>))
|
||||
using BasicTestRange = BasicTestViewOrRange<Iter, Sent, IsSized, false>;
|
||||
|
||||
#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H
|
||||
@@ -1173,6 +1173,11 @@ feature_test_macros = [
|
||||
"values": {"c++23": 202106},
|
||||
"headers": ["algorithm"],
|
||||
},
|
||||
{
|
||||
"name": "__cpp_lib_ranges_stride",
|
||||
"values": {"c++23": 202207},
|
||||
"headers": ["ranges"],
|
||||
},
|
||||
{
|
||||
"name": "__cpp_lib_ranges_to_container",
|
||||
"values": {"c++23": 202202},
|
||||
|
||||
Reference in New Issue
Block a user