diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv index e174cda1a7ca26..77239c314f787f 100644 --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -138,7 +138,7 @@ Section,Description,Dependencies,Assignee,Complete `[range.view.ref] `_,`ref-view `_,[view.interface],Zoe Carver,✅ `[range.filter] `_,filter_view,[range.all],Louis Dionne,Not started `[range.transform] `_,`transform_view `_,[range.all],Zoe Carver,✅ -`[range.iota] `_,iota_view,[range.all],Zoe Carver,In Progress +`[range.iota] `_,iota_view,[range.all],Zoe Carver,✅ `[range.take] `_,take_view,[range.all],Zoe Carver,✅ `[range.join] `_,join_view,[range.all],Zoe Carver,In Progress `[range.empty] `_,`empty_view `_,[view.interface],Zoe Carver,✅ diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index d2760ee45ad3c8..914c74c7ceb603 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -223,6 +223,7 @@ set(files __ranges/empty.h __ranges/enable_borrowed_range.h __ranges/enable_view.h + __ranges/iota_view.h __ranges/non_propagating_cache.h __ranges/ref_view.h __ranges/reverse_view.h diff --git a/libcxx/include/__iterator/concepts.h b/libcxx/include/__iterator/concepts.h index 6eb4aef10528a3..db836bda253911 100644 --- a/libcxx/include/__iterator/concepts.h +++ b/libcxx/include/__iterator/concepts.h @@ -72,6 +72,8 @@ concept __signed_integer_like = signed_integral<_Tp>; template concept weakly_incrementable = + // TODO: remove this once the clang bug is fixed (bugs.llvm.org/PR48173). + !same_as<_Ip, bool> && // Currently, clang does not handle bool correctly. movable<_Ip> && requires(_Ip __i) { typename iter_difference_t<_Ip>; diff --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h new file mode 100644 index 00000000000000..f302826b024746 --- /dev/null +++ b/libcxx/include/__ranges/iota_view.h @@ -0,0 +1,403 @@ +// -*- 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_IOTA_VIEW_H +#define _LIBCPP___RANGES_IOTA_VIEW_H + +#include <__config> +#include <__debug> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/unreachable_sentinel.h> +#include <__ranges/copyable_box.h> +#include <__ranges/enable_borrowed_range.h> +#include <__ranges/view_interface.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +namespace ranges { + template + struct __get_wider_signed { + static auto __call() { + if constexpr (sizeof(_Int) < sizeof(short)) return type_identity{}; + else if constexpr (sizeof(_Int) < sizeof(int)) return type_identity{}; + else if constexpr (sizeof(_Int) < sizeof(long)) return type_identity{}; + else return type_identity{}; + + static_assert(sizeof(_Int) <= sizeof(long long), + "Found integer-like type that is bigger than largest integer like type."); + } + + using type = typename decltype(__call())::type; + }; + + template + using _IotaDiffT = typename _If< + (!integral<_Start> || sizeof(iter_difference_t<_Start>) > sizeof(_Start)), + type_identity>, + __get_wider_signed<_Start> + >::type; + + template + concept __decrementable = incrementable<_Iter> && requires(_Iter __i) { + { --__i } -> same_as<_Iter&>; + { __i-- } -> same_as<_Iter>; + }; + + template + concept __advanceable = + __decrementable<_Iter> && totally_ordered<_Iter> && + requires(_Iter __i, const _Iter __j, const _IotaDiffT<_Iter> __n) { + { __i += __n } -> same_as<_Iter&>; + { __i -= __n } -> same_as<_Iter&>; + _Iter(__j + __n); + _Iter(__n + __j); + _Iter(__j - __n); + { __j - __j } -> convertible_to<_IotaDiffT<_Iter>>; + }; + + template + struct __iota_iterator_category {}; + + template + struct __iota_iterator_category<_Tp> { + using iterator_category = input_iterator_tag; + }; + + template + requires __weakly_equality_comparable_with<_Start, _Bound> && copyable<_Start> + class iota_view : public view_interface> { + struct __iterator : public __iota_iterator_category<_Start> { + friend class iota_view; + + using iterator_concept = + _If<__advanceable<_Start>, random_access_iterator_tag, + _If<__decrementable<_Start>, bidirectional_iterator_tag, + _If, forward_iterator_tag, + /*Else*/ input_iterator_tag>>>; + + using value_type = _Start; + using difference_type = _IotaDiffT<_Start>; + + _Start __value_ = _Start(); + + _LIBCPP_HIDE_FROM_ABI + __iterator() requires default_initializable<_Start> = default; + + _LIBCPP_HIDE_FROM_ABI + constexpr explicit __iterator(_Start __value) : __value_(_VSTD::move(__value)) {} + + _LIBCPP_HIDE_FROM_ABI + constexpr _Start operator*() const noexcept(is_nothrow_copy_constructible_v<_Start>) { + return __value_; + } + + _LIBCPP_HIDE_FROM_ABI + constexpr __iterator& operator++() { + ++__value_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI + constexpr void operator++(int) { ++*this; } + + _LIBCPP_HIDE_FROM_ABI + constexpr __iterator operator++(int) requires incrementable<_Start> { + auto __tmp = *this; + ++*this; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI + constexpr __iterator& operator--() requires __decrementable<_Start> { + --__value_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI + constexpr __iterator operator--(int) requires __decrementable<_Start> { + auto __tmp = *this; + --*this; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI + constexpr __iterator& operator+=(difference_type __n) + requires __advanceable<_Start> + { + if constexpr (__integer_like<_Start> && !__signed_integer_like<_Start>) { + if (__n >= difference_type(0)) { + __value_ += static_cast<_Start>(__n); + } else { + __value_ -= static_cast<_Start>(-__n); + } + } else { + __value_ += __n; + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI + constexpr __iterator& operator-=(difference_type __n) + requires __advanceable<_Start> + { + if constexpr (__integer_like<_Start> && !__signed_integer_like<_Start>) { + if (__n >= difference_type(0)) { + __value_ -= static_cast<_Start>(__n); + } else { + __value_ += static_cast<_Start>(-__n); + } + } else { + __value_ -= __n; + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI + constexpr _Start operator[](difference_type __n) const + requires __advanceable<_Start> + { + return _Start(__value_ + __n); + } + + _LIBCPP_HIDE_FROM_ABI + friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) + requires equality_comparable<_Start> + { + return __x.__value_ == __y.__value_; + } + + _LIBCPP_HIDE_FROM_ABI + friend constexpr bool operator<(const __iterator& __x, const __iterator& __y) + requires totally_ordered<_Start> + { + return __x.__value_ < __y.__value_; + } + + _LIBCPP_HIDE_FROM_ABI + friend constexpr bool operator>(const __iterator& __x, const __iterator& __y) + requires totally_ordered<_Start> + { + return __y < __x; + } + + _LIBCPP_HIDE_FROM_ABI + friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y) + requires totally_ordered<_Start> + { + return !(__y < __x); + } + + _LIBCPP_HIDE_FROM_ABI + friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y) + requires totally_ordered<_Start> + { + return !(__x < __y); + } + +// friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y) +// requires totally_ordered<_Start> && three_way_comparable<_Start> +// { +// return __x.__value_ <=> __y.__value_; +// } + + _LIBCPP_HIDE_FROM_ABI + friend constexpr __iterator operator+(__iterator __i, difference_type __n) + requires __advanceable<_Start> + { + __i += __n; + return __i; + } + + _LIBCPP_HIDE_FROM_ABI + friend constexpr __iterator operator+(difference_type __n, __iterator __i) + requires __advanceable<_Start> + { + return __i + __n; + } + + _LIBCPP_HIDE_FROM_ABI + friend constexpr __iterator operator-(__iterator __i, difference_type __n) + requires __advanceable<_Start> + { + __i -= __n; + return __i; + } + + _LIBCPP_HIDE_FROM_ABI + friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y) + requires __advanceable<_Start> + { + if constexpr (__integer_like<_Start>) { + if constexpr (__signed_integer_like<_Start>) { + return difference_type(difference_type(__x.__value_) - difference_type(__y.__value_)); + } + if (__y.__value_ > __x.__value_) { + return difference_type(-difference_type(__y.__value_ - __x.__value_)); + } + return difference_type(__x.__value_ - __y.__value_); + } + return __x.__value_ - __y.__value_; + } + }; + + struct __sentinel { + friend class iota_view; + + private: + _Bound __bound_ = _Bound(); + + public: + _LIBCPP_HIDE_FROM_ABI + __sentinel() = default; + constexpr explicit __sentinel(_Bound __bound) : __bound_(_VSTD::move(__bound)) {} + + _LIBCPP_HIDE_FROM_ABI + friend constexpr bool operator==(const __iterator& __x, const __sentinel& __y) { + return __x.__value_ == __y.__bound_; + } + + _LIBCPP_HIDE_FROM_ABI + friend constexpr iter_difference_t<_Start> operator-(const __iterator& __x, const __sentinel& __y) + requires sized_sentinel_for<_Bound, _Start> + { + return __x.__value_ - __y.__bound_; + } + + _LIBCPP_HIDE_FROM_ABI + friend constexpr iter_difference_t<_Start> operator-(const __sentinel& __x, const __iterator& __y) + requires sized_sentinel_for<_Bound, _Start> + { + return -(__y - __x); + } + }; + + _Start __value_ = _Start(); + _Bound __bound_ = _Bound(); + + public: + _LIBCPP_HIDE_FROM_ABI + iota_view() requires default_initializable<_Start> = default; + + _LIBCPP_HIDE_FROM_ABI + constexpr explicit iota_view(_Start __value) : __value_(_VSTD::move(__value)) { } + + _LIBCPP_HIDE_FROM_ABI + constexpr iota_view(type_identity_t<_Start> __value, type_identity_t<_Bound> __bound) + : __value_(_VSTD::move(__value)), __bound_(_VSTD::move(__bound)) { + // Validate the precondition if possible. + if constexpr (totally_ordered_with<_Start, _Bound>) { + _LIBCPP_ASSERT(ranges::less_equal()(__value_, __bound_), + "Precondition violated: value is greater than bound."); + } + } + + _LIBCPP_HIDE_FROM_ABI + constexpr iota_view(__iterator __first, __iterator __last) + requires same_as<_Start, _Bound> + : iota_view(_VSTD::move(__first.__value_), _VSTD::move(__last.__value_)) {} + + _LIBCPP_HIDE_FROM_ABI + constexpr iota_view(__iterator __first, _Bound __last) + requires same_as<_Bound, unreachable_sentinel_t> + : iota_view(_VSTD::move(__first.__value_), _VSTD::move(__last)) {} + + _LIBCPP_HIDE_FROM_ABI + constexpr iota_view(__iterator __first, __sentinel __last) + requires (!same_as<_Start, _Bound> && !same_as<_Start, unreachable_sentinel_t>) + : iota_view(_VSTD::move(__first.__value_), _VSTD::move(__last.__bound_)) {} + + _LIBCPP_HIDE_FROM_ABI + constexpr __iterator begin() const { return __iterator{__value_}; } + + _LIBCPP_HIDE_FROM_ABI + constexpr auto end() const { + if constexpr (same_as<_Bound, unreachable_sentinel_t>) + return unreachable_sentinel; + else + return __sentinel{__bound_}; + } + + _LIBCPP_HIDE_FROM_ABI + constexpr __iterator end() const requires same_as<_Start, _Bound> { + return __iterator{__bound_}; + } + + _LIBCPP_HIDE_FROM_ABI + constexpr auto size() const + requires (same_as<_Start, _Bound> && __advanceable<_Start>) || + (integral<_Start> && integral<_Bound>) || + sized_sentinel_for<_Bound, _Start> + { + if constexpr (__integer_like<_Start> && __integer_like<_Bound>) { + if (__value_ < 0) { + if (__bound_ < 0) { + return _VSTD::__to_unsigned_like(-__value_) - _VSTD::__to_unsigned_like(-__bound_); + } + return _VSTD::__to_unsigned_like(__bound_) + _VSTD::__to_unsigned_like(-__value_); + } + return _VSTD::__to_unsigned_like(__bound_) - _VSTD::__to_unsigned_like(__value_); + } + return _VSTD::__to_unsigned_like(__bound_ - __value_); + } + }; + + template + requires (!__integer_like<_Start> || !__integer_like<_Bound> || + (__signed_integer_like<_Start> == __signed_integer_like<_Bound>)) + iota_view(_Start, _Bound) -> iota_view<_Start, _Bound>; + + template + inline constexpr bool enable_borrowed_range> = true; +} // namespace ranges + +namespace views { +namespace __iota { + struct __fn { + template + _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Start&& __start) const + noexcept(noexcept(ranges::iota_view(_VSTD::forward<_Start>(__start)))) + -> decltype(ranges::iota_view(_VSTD::forward<_Start>(__start))) + { + return ranges::iota_view(_VSTD::forward<_Start>(__start)); + } + + template + _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Start&& __start, _Bound&& __bound) const + noexcept(noexcept(ranges::iota_view(_VSTD::forward<_Start>(__start), _VSTD::forward<_Bound>(__bound)))) + -> decltype(ranges::iota_view(_VSTD::forward<_Start>(__start), _VSTD::forward<_Bound>(__bound))) + { + return ranges::iota_view(_VSTD::forward<_Start>(__start), _VSTD::forward<_Bound>(__bound)); + } + }; +} // namespace __iota + +inline namespace __cpo { + inline constexpr auto iota = __iota::__fn{}; +} +} // namespace views + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANGES_IOTA_VIEW_H diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index f7c899c5fe5359..079dff201804b8 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -658,6 +658,7 @@ module std [system] { module empty_view { private header "__ranges/empty_view.h" } module enable_borrowed_range { private header "__ranges/enable_borrowed_range.h" } module enable_view { private header "__ranges/enable_view.h" } + module iota_view { private header "__ranges/iota_view.h" } module non_propagating_cache { private header "__ranges/non_propagating_cache.h" } module ref_view { private header "__ranges/ref_view.h" } module reverse_view { private header "__ranges/reverse_view.h" } diff --git a/libcxx/include/ranges b/libcxx/include/ranges index 49e79647739c8f..df8d4194ffa143 100644 --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -177,6 +177,13 @@ namespace std::ranges { template requires is_object_v class single_view; + + template + requires weakly-equality-comparable-with && copyable + class iota_view; + + template + inline constexpr bool enable_borrowed_range> = true; } */ @@ -199,6 +206,7 @@ namespace std::ranges { #include <__ranges/empty_view.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/enable_view.h> +#include <__ranges/iota_view.h> #include <__ranges/ref_view.h> #include <__ranges/reverse_view.h> #include <__ranges/take_view.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/ranges/iota_view.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/iota_view.module.verify.cpp new file mode 100644 index 00000000000000..8b2d4cad2da251 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/iota_view.module.verify.cpp @@ -0,0 +1,16 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__ranges/iota_view.h'}} +#include <__ranges/iota_view.h> diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.winc/weakly_incrementable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.winc/weakly_incrementable.compile.pass.cpp index a3198357bbb76b..5fad38d4d6cfdc 100644 --- a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.winc/weakly_incrementable.compile.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.winc/weakly_incrementable.compile.pass.cpp @@ -30,6 +30,7 @@ static_assert(!std::weakly_incrementable); static_assert(!std::weakly_incrementable); static_assert(!std::weakly_incrementable); static_assert(!std::weakly_incrementable); +static_assert(!std::weakly_incrementable); struct S {}; static_assert(!std::weakly_incrementable); diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/begin.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/begin.pass.cpp new file mode 100644 index 00000000000000..16b80b19ef3b3f --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/begin.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// constexpr iterator begin() const; + +#include +#include + +#include "test_macros.h" +#include "types.h" + +template +constexpr void testType() { + { + std::ranges::iota_view io(T(0)); + assert(*io.begin() == T(0)); + } + { + std::ranges::iota_view io(T(10)); + assert(*io.begin() == T(10)); + assert(*std::move(io).begin() == T(10)); + } + { + const std::ranges::iota_view io(T(0)); + assert(*io.begin() == T(0)); + } + { + const std::ranges::iota_view io(T(10)); + assert(*io.begin() == T(10)); + } +} + +constexpr bool test() { + testType(); + testType(); + testType(); + testType(); + testType(); + testType(); + testType(); + testType(); + testType(); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/borrowing.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/borrowing.compile.pass.cpp new file mode 100644 index 00000000000000..7fbf987463652f --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/borrowing.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// template +// inline constexpr bool enable_borrowed_range> = true; + +#include +#include +#include + +#include "test_macros.h" +#include "types.h" + +static_assert(std::ranges::enable_borrowed_range>); +static_assert(std::ranges::enable_borrowed_range>); +static_assert(std::ranges::enable_borrowed_range>>); diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/ctad.compile.pass.cpp new file mode 100644 index 00000000000000..d1f4e5a5f45038 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/ctad.compile.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// template +// requires (!is-integer-like || !is-integer-like || +// (is-signed-integer-like == is-signed-integer-like)) +// iota_view(W, Bound) -> iota_view; + +#include +#include +#include + +#include "test_macros.h" +#include "types.h" + +template +concept CanDeduce = requires(const T& t, const U& u) { + std::ranges::iota_view(t, u); +}; + +void test() { + static_assert(std::same_as< + decltype(std::ranges::iota_view(0, 0)), + std::ranges::iota_view + >); + + static_assert(std::same_as< + decltype(std::ranges::iota_view(0)), + std::ranges::iota_view + >); + + static_assert(std::same_as< + decltype(std::ranges::iota_view(0, std::unreachable_sentinel)), + std::ranges::iota_view + >); + + static_assert(std::same_as< + decltype(std::ranges::iota_view(0, IntComparableWith(0))), + std::ranges::iota_view> + >); + + static_assert( CanDeduce); + static_assert(!CanDeduce); + static_assert(!CanDeduce); +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.default.pass.cpp new file mode 100644 index 00000000000000..724656429f7d6a --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.default.pass.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// iota_view() requires default_­initializable = default; + +#include +#include + +#include "test_macros.h" +#include "types.h" + +constexpr bool test() { + { + std::ranges::iota_view> io; + assert((*io.begin()).value_ == 42); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + static_assert(!std::default_initializable>); + static_assert( std::default_initializable>); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.first.last.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.first.last.pass.cpp new file mode 100644 index 00000000000000..61eb8a2d16732e --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.first.last.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// constexpr iota_view(iterator first, see below last); + +#include +#include + +#include "test_macros.h" +#include "types.h" + +constexpr bool test() { + { + std::ranges::iota_view commonView(SomeInt(0), SomeInt(10)); + std::ranges::iota_view io(commonView.begin(), commonView.end()); + assert(std::ranges::next(io.begin(), 10) == io.end()); + } + + { + std::ranges::iota_view unreachableSent(SomeInt(0)); + std::ranges::iota_view io(unreachableSent.begin(), std::unreachable_sentinel); + assert(std::ranges::next(io.begin(), 10) != io.end()); + } + + { + std::ranges::iota_view differentTypes(SomeInt(0), IntComparableWith(SomeInt(10))); + std::ranges::iota_view> io(differentTypes.begin(), differentTypes.end()); + assert(std::ranges::next(io.begin(), 10) == io.end()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} + diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.bound.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.bound.pass.cpp new file mode 100644 index 00000000000000..21f5558f61d816 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.bound.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// ADDITIONAL_COMPILE_FLAGS: -Wno-sign-compare + +// constexpr iota_view(type_identity_t value, type_identity_t bound); + +#include +#include + +#include "test_macros.h" +#include "types.h" + +constexpr bool test() { + { + std::ranges::iota_view io(SomeInt(0), SomeInt(10)); + assert(std::ranges::next(io.begin(), 10) == io.end()); + } + + { + std::ranges::iota_view io(SomeInt(0), std::unreachable_sentinel); + assert(std::ranges::next(io.begin(), 10) != io.end()); + } + + { + std::ranges::iota_view> io(SomeInt(0), IntComparableWith(SomeInt(10))); + assert(std::ranges::next(io.begin(), 10) == io.end()); + } + + { + // This is allowed only when using the constructor (not the deduction guide). + std::ranges::iota_view signedUnsigned(0, 10); + assert(std::ranges::next(signedUnsigned.begin(), 10) == signedUnsigned.end()); + } + + { + // This is allowed only when using the constructor (not the deduction guide). + std::ranges::iota_view signedUnsigned(0, 10); + assert(std::ranges::next(signedUnsigned.begin(), 10) == signedUnsigned.end()); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} + diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.pass.cpp new file mode 100644 index 00000000000000..cc65b9368a2f98 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/ctor.value.pass.cpp @@ -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 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// constexpr explicit iota_view(W value); + +#include +#include + +#include "test_macros.h" +#include "types.h" + +struct SomeIntComparable { + using difference_type = int; + + SomeInt value_; + constexpr SomeIntComparable() : value_(SomeInt(10)) {} + + friend constexpr bool operator==(SomeIntComparable lhs, SomeIntComparable rhs) { + return lhs.value_ == rhs.value_; + } + friend constexpr bool operator==(SomeIntComparable lhs, SomeInt rhs) { + return lhs.value_ == rhs; + } + friend constexpr bool operator==(SomeInt lhs, SomeIntComparable rhs) { + return lhs == rhs.value_; + } + + friend constexpr difference_type operator-(SomeIntComparable lhs, SomeIntComparable rhs) { + return lhs.value_ - rhs.value_; + } + + constexpr SomeIntComparable& operator++() { ++value_; return *this; } + constexpr SomeIntComparable operator++(int) { auto tmp = *this; ++value_; return tmp; } + constexpr SomeIntComparable operator--() { --value_; return *this; } +}; + +constexpr bool test() { + { + std::ranges::iota_view io(SomeInt(42)); + assert((*io.begin()).value_ == 42); + // Check that end returns std::unreachable_sentinel. + assert(io.end() != io.begin()); + static_assert(std::same_as); + } + + { + std::ranges::iota_view io(SomeInt(0)); + assert(std::ranges::next(io.begin(), 10) == io.end()); + } + { + static_assert(!std::is_convertible_v, SomeInt>); + static_assert( std::is_constructible_v, SomeInt>); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/end.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/end.pass.cpp new file mode 100644 index 00000000000000..418a52a3b9d2fc --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/end.pass.cpp @@ -0,0 +1,82 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// ADDITIONAL_COMPILE_FLAGS: -Wno-sign-compare + +// constexpr auto end() const; +// constexpr iterator end() const requires same_as; + +#include +#include + +#include "test_macros.h" +#include "types.h" + +template +constexpr void testType(U u) { + { + std::ranges::iota_view io(T(0), u); + assert(std::ranges::next(io.begin(), 10) == io.end()); + } + { + std::ranges::iota_view io(T(10), u); + assert(io.begin() == io.end()); + assert(io.begin() == std::move(io).end()); + } + { + const std::ranges::iota_view io(T(0), u); + assert(std::ranges::next(io.begin(), 10) == io.end()); + assert(std::ranges::next(io.begin(), 10) == std::move(io).end()); + } + { + const std::ranges::iota_view io(T(10), u); + assert(io.begin() == io.end()); + } + + { + std::ranges::iota_view io(T(0), std::unreachable_sentinel); + assert(io.begin() != io.end()); + assert(std::ranges::next(io.begin()) != io.end()); + assert(std::ranges::next(io.begin(), 10) != io.end()); + } + { + const std::ranges::iota_view io(T(0), std::unreachable_sentinel); + assert(io.begin() != io.end()); + assert(std::ranges::next(io.begin()) != io.end()); + assert(std::ranges::next(io.begin(), 10) != io.end()); + } +} + +constexpr bool test() { + testType(SomeInt(10)); + testType(IntComparableWith(SomeInt(10))); + testType(IntComparableWith(10)); + testType(IntComparableWith(10)); + testType(IntComparableWith(10)); + testType(int(10)); + testType(unsigned(10)); + testType(unsigned(10)); + testType(int(10)); + testType(IntComparableWith(10)); + testType(short(10)); + testType(IntComparableWith(10)); + testType(IntComparableWith(10)); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/compare.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/compare.pass.cpp new file mode 100644 index 00000000000000..6ef4751c644084 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/compare.pass.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// friend constexpr bool operator<(const iterator& x, const iterator& y) +// requires totally_ordered; +// friend constexpr bool operator>(const iterator& x, const iterator& y) +// requires totally_ordered; +// friend constexpr bool operator<=(const iterator& x, const iterator& y) +// requires totally_ordered; +// friend constexpr bool operator>=(const iterator& x, const iterator& y) +// requires totally_ordered; +// friend constexpr bool operator==(const iterator& x, const iterator& y) +// requires equality_comparable; + +// TODO: test spaceship operator once it's implemented. + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +constexpr bool test() { + { + const std::ranges::iota_view io(0); + assert( io.begin() == io.begin() ); + assert( io.begin() != std::ranges::next(io.begin())); + assert( io.begin() < std::ranges::next(io.begin())); + assert(std::ranges::next(io.begin()) > io.begin() ); + assert( io.begin() <= std::ranges::next(io.begin())); + assert(std::ranges::next(io.begin()) >= io.begin() ); + assert( io.begin() <= io.begin() ); + assert( io.begin() >= io.begin() ); + } + { + std::ranges::iota_view io(0); + assert( io.begin() == io.begin() ); + assert( io.begin() != std::ranges::next(io.begin())); + assert( io.begin() < std::ranges::next(io.begin())); + assert(std::ranges::next(io.begin()) > io.begin() ); + assert( io.begin() <= std::ranges::next(io.begin())); + assert(std::ranges::next(io.begin()) >= io.begin() ); + assert( io.begin() <= io.begin() ); + assert( io.begin() >= io.begin() ); + } + { + const std::ranges::iota_view io(SomeInt(0)); + assert( io.begin() == io.begin() ); + assert( io.begin() != std::ranges::next(io.begin())); + assert( io.begin() < std::ranges::next(io.begin())); + assert(std::ranges::next(io.begin()) > io.begin() ); + assert( io.begin() <= std::ranges::next(io.begin())); + assert(std::ranges::next(io.begin()) >= io.begin() ); + assert( io.begin() <= io.begin() ); + assert( io.begin() >= io.begin() ); + } + { + std::ranges::iota_view io(SomeInt(0)); + assert( io.begin() == io.begin() ); + assert( io.begin() != std::ranges::next(io.begin())); + assert( io.begin() < std::ranges::next(io.begin())); + assert(std::ranges::next(io.begin()) > io.begin() ); + assert( io.begin() <= std::ranges::next(io.begin())); + assert(std::ranges::next(io.begin()) >= io.begin() ); + assert( io.begin() <= io.begin() ); + assert( io.begin() >= io.begin() ); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.default.pass.cpp new file mode 100644 index 00000000000000..ac8075dba91430 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.default.pass.cpp @@ -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 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// iterator() requires default_initializable = default; + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +constexpr bool test() { + using Iter = std::ranges::iterator_t>>; + Iter iter; + assert((*iter).value_ == 42); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.pass.cpp new file mode 100644 index 00000000000000..8395dde50df4f6 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// constexpr explicit iterator(W value); + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +constexpr bool test() { + { + using Iter = std::ranges::iterator_t>; + auto iter = Iter(42); + assert(*iter == 42); + } + { + using Iter = std::ranges::iterator_t>; + auto iter = Iter(SomeInt(42)); + assert(*iter == SomeInt(42)); + } + { + using Iter = std::ranges::iterator_t>; + static_assert(!std::is_convertible_v); + static_assert( std::is_constructible_v); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/decrement.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/decrement.pass.cpp new file mode 100644 index 00000000000000..a17dc3f99f4721 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/decrement.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// constexpr iterator& operator--() requires decrementable; +// constexpr iterator operator--(int) requires decrementable; + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +template +concept Decrementable = + requires(T i) { + --i; + } || + requires(T i) { + i--; + }; + +constexpr bool test() { + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin()); + auto iter2 = std::next(io.begin()); + assert(iter1 == iter2); + assert(--iter1 != iter2--); + assert(iter1 == iter2); + + static_assert(!std::is_reference_v); + static_assert( std::is_reference_v); + static_assert(std::same_as, decltype(iter2--)>); + } + { + std::ranges::iota_view io(SomeInt(0)); + auto iter1 = std::next(io.begin()); + auto iter2 = std::next(io.begin()); + assert(iter1 == iter2); + assert(--iter1 != iter2--); + assert(iter1 == iter2); + + static_assert(!std::is_reference_v); + static_assert( std::is_reference_v); + static_assert(std::same_as, decltype(iter2--)>); + } + + static_assert(!Decrementable>); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/increment.pass.cpp new file mode 100644 index 00000000000000..cbc143e20a0d69 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/increment.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// constexpr iterator& operator++(); +// constexpr void operator++(int); +// constexpr iterator operator++(int) requires incrementable; + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +constexpr bool test() { + { + std::ranges::iota_view io(0); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + assert(++iter1 != iter2++); + assert(iter1 == iter2); + + static_assert(!std::is_reference_v); + static_assert( std::is_reference_v); + static_assert(std::same_as, decltype(iter2++)>); + } + { + std::ranges::iota_view io(SomeInt(0)); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + assert(++iter1 != iter2++); + assert(iter1 == iter2); + + static_assert(!std::is_reference_v); + static_assert( std::is_reference_v); + static_assert(std::same_as, decltype(iter2++)>); + } + + { + std::ranges::iota_view io(NotIncrementable(0)); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + assert(++iter1 != iter2); + iter2++; + assert(iter1 == iter2); + + static_assert(std::same_as); + static_assert(std::is_reference_v); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp new file mode 100644 index 00000000000000..26d6bafbe5eedc --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp @@ -0,0 +1,163 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// Test iterator category and iterator concepts. + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +struct Decrementable { + using difference_type = int; + + auto operator<=>(const Decrementable&) const = default; + + constexpr Decrementable& operator++(); + constexpr Decrementable operator++(int); + constexpr Decrementable& operator--(); + constexpr Decrementable operator--(int); +}; + +struct Incrementable { + using difference_type = int; + + auto operator<=>(const Incrementable&) const = default; + + constexpr Incrementable& operator++(); + constexpr Incrementable operator++(int); +}; + +struct BigType { + char buffer[128]; + + using difference_type = int; + + auto operator<=>(const BigType&) const = default; + + constexpr BigType& operator++(); + constexpr BigType operator++(int); +}; + +struct CharDifferenceType { + using difference_type = signed char; + + auto operator<=>(const CharDifferenceType&) const = default; + + constexpr CharDifferenceType& operator++(); + constexpr CharDifferenceType operator++(int); +}; + +template +concept HasIteratorCategory = requires { typename std::ranges::iterator_t::iterator_category; }; + +void test() { + { + const std::ranges::iota_view io(0); + using Iter = decltype(io.begin()); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(sizeof(Iter::difference_type) > sizeof(char)); + static_assert(std::is_signed_v); + LIBCPP_STATIC_ASSERT(std::same_as); + } + { + const std::ranges::iota_view io(0); + using Iter = decltype(io.begin()); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(sizeof(Iter::difference_type) > sizeof(short)); + static_assert(std::is_signed_v); + LIBCPP_STATIC_ASSERT(std::same_as); + } + { + const std::ranges::iota_view io(0); + using Iter = decltype(io.begin()); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(sizeof(Iter::difference_type) > sizeof(int)); + static_assert(std::is_signed_v); + // If we're compiling for 32 bit or windows, int and long are the same size, so long long is the correct difference type. +#if INTPTR_MAX == INT32_MAX || defined(_WIN32) + LIBCPP_STATIC_ASSERT(std::same_as); +#else + LIBCPP_STATIC_ASSERT(std::same_as); +#endif + } + { + const std::ranges::iota_view io(0); + using Iter = decltype(io.begin()); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + // Same as below, if there is no type larger than long, we can just use that. + static_assert(sizeof(Iter::difference_type) >= sizeof(long)); + static_assert(std::is_signed_v); + LIBCPP_STATIC_ASSERT(std::same_as); + } + { + const std::ranges::iota_view io(0); + using Iter = decltype(io.begin()); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + // No integer is larger than long long, so it is OK to use long long as the difference type here: + // https://eel.is/c++draft/range.iota.view#1.3 + static_assert(sizeof(Iter::difference_type) >= sizeof(long long)); + static_assert(std::is_signed_v); + LIBCPP_STATIC_ASSERT(std::same_as); + } + { + const std::ranges::iota_view io; + using Iter = decltype(io.begin()); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + } + { + const std::ranges::iota_view io; + using Iter = decltype(io.begin()); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + } + { + const std::ranges::iota_view io(NotIncrementable(0)); + using Iter = decltype(io.begin()); + static_assert(std::same_as); + static_assert(!HasIteratorCategory>); + static_assert(std::same_as); + static_assert(std::same_as); + } + { + const std::ranges::iota_view io; + using Iter = decltype(io.begin()); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + } + { + const std::ranges::iota_view io; + using Iter = decltype(io.begin()); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + } +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus.pass.cpp new file mode 100644 index 00000000000000..f4181801a948ff --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus.pass.cpp @@ -0,0 +1,179 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// friend constexpr iterator operator-(iterator i, difference_type n) +// requires advanceable; +// friend constexpr difference_type operator-(const iterator& x, const iterator& y) +// requires advanceable; + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +// If we're compiling for 32 bit or windows, int and long are the same size, so long long is the correct difference type. +#if INTPTR_MAX == INT32_MAX || defined(_WIN32) +using IntDiffT = long long; +#else +using IntDiffT = long; +#endif + +constexpr bool test() { + // - difference_type + { + // When "_Start" is signed integer like. + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 == iter2); + assert(iter1 - 5 != iter2); + assert(iter1 - 5 == std::ranges::prev(iter2, 5)); + + static_assert(!std::is_reference_v); + } + + // When "_Start" is not integer like. + { + std::ranges::iota_view io(SomeInt(0)); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 == iter2); + assert(iter1 - 5 != iter2); + assert(iter1 - 5 == std::ranges::prev(iter2, 5)); + + static_assert(!std::is_reference_v); + } + + // When "_Start" is unsigned integer like and n is greater than or equal to zero. + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 == iter2); + assert(iter1 - 5 != iter2); + assert(iter1 - 5 == std::ranges::prev(iter2, 5)); + + static_assert(!std::is_reference_v); + } + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 - 0 == iter2); + } + + // When "_Start" is unsigned integer like and n is less than zero. + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 - 5 != iter2); + assert(iter1 - 5 == std::ranges::prev(iter2, 5)); + + static_assert(!std::is_reference_v); + } + } + + // - + { + // When "_Start" is signed integer like. + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 5); + assert(iter1 - iter2 == 5); + + LIBCPP_STATIC_ASSERT(std::same_as); + } + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 - iter2 == 0); + + LIBCPP_STATIC_ASSERT(std::same_as); + } + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 5); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 - iter2 == -5); + + LIBCPP_STATIC_ASSERT(std::same_as); + } + + // When "_Start" is unsigned integer like and y > x. + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 5); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 - iter2 == -5); + + LIBCPP_STATIC_ASSERT(std::same_as); + } + + // When "_Start" is unsigned integer like and x >= y. + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 5); + assert(iter1 - iter2 == 5); + + LIBCPP_STATIC_ASSERT(std::same_as); + } + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 - iter2 == 0); + + LIBCPP_STATIC_ASSERT(std::same_as); + } + + // When "_Start" is not integer like. + { + std::ranges::iota_view io(SomeInt(0)); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 5); + assert(iter1 - iter2 == 5); + + static_assert(std::same_as); + } + { + std::ranges::iota_view io(SomeInt(0)); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 - iter2 == 0); + + static_assert(std::same_as); + } + { + std::ranges::iota_view io(SomeInt(0)); + auto iter1 = std::next(io.begin(), 5); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 - iter2 == -5); + + static_assert(std::same_as); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus_eq.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus_eq.pass.cpp new file mode 100644 index 00000000000000..6616ebbb0a2aee --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/minus_eq.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// constexpr iterator& operator-=(difference_type n) +// requires advanceable; + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +constexpr bool test() { + // When "_Start" is signed integer like. + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 == iter2); + iter1 -= 5; + assert(iter1 != iter2); + assert(iter1 == std::ranges::prev(iter2, 5)); + + static_assert(std::is_reference_v); + } + + // When "_Start" is not integer like. + { + std::ranges::iota_view io(SomeInt(0)); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 == iter2); + iter1 -= 5; + assert(iter1 != iter2); + assert(iter1 == std::ranges::prev(iter2, 5)); + + static_assert(std::is_reference_v); + } + + // When "_Start" is unsigned integer like and n is greater than or equal to zero. + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 == iter2); + iter1 -= 5; + assert(iter1 != iter2); + assert(iter1 == std::ranges::prev(iter2, 5)); + + static_assert(std::is_reference_v); + } + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 == iter2); + iter1 -= 0; + assert(iter1 == iter2); + } + + // When "_Start" is unsigned integer like and n is less than zero. + { + std::ranges::iota_view io(0); + auto iter1 = std::next(io.begin(), 10); + auto iter2 = std::next(io.begin(), 10); + assert(iter1 == iter2); + iter1 -= -5; + assert(iter1 != iter2); + assert(iter1 == std::ranges::next(iter2, 5)); + + static_assert(std::is_reference_v); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus.pass.cpp new file mode 100644 index 00000000000000..b844900b3dd422 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus.pass.cpp @@ -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 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// friend constexpr iterator operator+(iterator i, difference_type n) +// requires advanceable; +// friend constexpr iterator operator+(difference_type n, iterator i) +// requires advanceable; + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +constexpr bool test() { + // When "_Start" is signed integer like. + { + std::ranges::iota_view io(0); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + assert(iter1 + 5 != iter2); + assert(iter1 + 5 == std::ranges::next(iter2, 5)); + + static_assert(std::is_reference_v); + } + + // When "_Start" is not integer like. + { + std::ranges::iota_view io(SomeInt(0)); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + assert(iter1 + 5 != iter2); + assert(iter1 + 5 == std::ranges::next(iter2, 5)); + + static_assert(std::is_reference_v); + } + + // When "_Start" is unsigned integer like and n is greater than or equal to zero. + { + std::ranges::iota_view io(0); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + assert(iter1 + 5 != iter2); + assert(iter1 + 5 == std::ranges::next(iter2, 5)); + + static_assert(std::is_reference_v); + } + { + std::ranges::iota_view io(0); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + assert(iter1 + 0 == iter2); + } + + // When "_Start" is unsigned integer like and n is less than zero. + { + std::ranges::iota_view io(0); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + assert(iter1 + 5 != iter2); + assert(iter1 + 5 == std::ranges::next(iter2, 5)); + + static_assert(std::is_reference_v); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus_eq.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus_eq.pass.cpp new file mode 100644 index 00000000000000..db3e6bdbcf287b --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/plus_eq.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// constexpr iterator& operator+=(difference_type n) +// requires advanceable; + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +constexpr bool test() { + // When "_Start" is signed integer like. + { + std::ranges::iota_view io(0); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + iter1 += 5; + assert(iter1 != iter2); + assert(iter1 == std::ranges::next(iter2, 5)); + + static_assert(std::is_reference_v); + } + + // When "_Start" is not integer like. + { + std::ranges::iota_view io(SomeInt(0)); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + iter1 += 5; + assert(iter1 != iter2); + assert(iter1 == std::ranges::next(iter2, 5)); + + static_assert(std::is_reference_v); + } + + // When "_Start" is unsigned integer like and n is greater than or equal to zero. + { + std::ranges::iota_view io(0); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + iter1 += 5; + assert(iter1 != iter2); + assert(iter1 == std::ranges::next(iter2, 5)); + + static_assert(std::is_reference_v); + } + { + std::ranges::iota_view io(0); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + iter1 += 0; + assert(iter1 == iter2); + } + + // When "_Start" is unsigned integer like and n is less than zero. + { + std::ranges::iota_view io(0); + auto iter1 = io.begin(); + auto iter2 = io.begin(); + assert(iter1 == iter2); + iter1 += 5; + assert(iter1 != iter2); + assert(iter1 == std::ranges::next(iter2, 5)); + + static_assert(std::is_reference_v); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/star.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/star.pass.cpp new file mode 100644 index 00000000000000..492d7333fa9a0d --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/star.pass.cpp @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// ADDITIONAL_COMPILE_FLAGS: -Wno-sign-compare + +// constexpr W operator*() const noexcept(is_nothrow_copy_constructible_v); + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +struct NotNoexceptCopy { + using difference_type = int; + + int value_; + constexpr explicit NotNoexceptCopy(int value = 0) : value_(value) {} + NotNoexceptCopy(const NotNoexceptCopy&) noexcept(false) = default; + + bool operator==(const NotNoexceptCopy&) const = default; + + friend constexpr NotNoexceptCopy& operator+=(NotNoexceptCopy &lhs, const NotNoexceptCopy& rhs) { + lhs.value_ += rhs.value_; return lhs; + } + friend constexpr NotNoexceptCopy& operator-=(NotNoexceptCopy &lhs, const NotNoexceptCopy& rhs) { + lhs.value_ -= rhs.value_; return lhs; + } + + friend constexpr NotNoexceptCopy operator+(NotNoexceptCopy lhs, NotNoexceptCopy rhs) { + return NotNoexceptCopy{lhs.value_ + rhs.value_}; + } + friend constexpr int operator-(NotNoexceptCopy lhs, NotNoexceptCopy rhs) { + return lhs.value_ - rhs.value_; + } + + constexpr NotNoexceptCopy& operator++() { ++value_; return *this; } + constexpr void operator++(int) { ++value_; } +}; + +template +constexpr void testType() { + { + std::ranges::iota_view io(T(0)); + auto iter = io.begin(); + for (int i = 0; i < 100; ++i, ++iter) + assert(*iter == T(i)); + + static_assert(noexcept(*iter) == !std::same_as); + } + { + std::ranges::iota_view io(T(10)); + auto iter = io.begin(); + for (int i = 10; i < 100; ++i, ++iter) + assert(*iter == T(i)); + } + { + const std::ranges::iota_view io(T(0)); + auto iter = io.begin(); + for (int i = 0; i < 100; ++i, ++iter) + assert(*iter == T(i)); + } + { + const std::ranges::iota_view io(T(10)); + auto iter = io.begin(); + for (int i = 10; i < 100; ++i, ++iter) + assert(*iter == T(i)); + } +} + +constexpr bool test() { + testType(); + testType(); + testType(); + testType(); + testType(); + testType(); + testType(); + testType(); + + // Tests a mix of signed unsigned types. + { + const std::ranges::iota_view io(0, 10); + auto iter = io.begin(); + for (int i = 0; i < 10; ++i, ++iter) + assert(*iter == i); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/subscript.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/subscript.pass.cpp new file mode 100644 index 00000000000000..0fe4ea7048ca74 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/subscript.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// constexpr W operator[](difference_type n) const +// requires advanceable; + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +template +constexpr void testType() { + { + std::ranges::iota_view io(T(0)); + auto iter = io.begin(); + for (int i = 0; i < 100; ++i) + assert(iter[i] == T(i)); + } + { + std::ranges::iota_view io(T(10)); + auto iter = io.begin(); + for (int i = 0; i < 100; ++i) + assert(iter[i] == T(i + 10)); + } + { + const std::ranges::iota_view io(T(0)); + auto iter = io.begin(); + for (int i = 0; i < 100; ++i) + assert(iter[i] == T(i)); + } + { + const std::ranges::iota_view io(T(10)); + auto iter = io.begin(); + for (int i = 0; i < 100; ++i) + assert(iter[i] == T(i + 10)); + } +} + +constexpr bool test() { + testType(); + testType(); + testType(); + testType(); + testType(); + testType(); + testType(); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/range_concept_conformance.compile.pass.cpp new file mode 100644 index 00000000000000..b125f76de9e491 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// Test that iota_view conforms to range and view concepts. + +#include + +#include "types.h" + +struct Decrementable { + using difference_type = int; + + auto operator<=>(const Decrementable&) const = default; + + constexpr Decrementable& operator++(); + constexpr Decrementable operator++(int); + constexpr Decrementable& operator--(); + constexpr Decrementable operator--(int); +}; + +struct Incrementable { + using difference_type = int; + + auto operator<=>(const Incrementable&) const = default; + + constexpr Incrementable& operator++(); + constexpr Incrementable operator++(int); +}; + +static_assert(std::ranges::random_access_range>); +static_assert(std::ranges::random_access_range>); +static_assert(std::ranges::bidirectional_range>); +static_assert(std::ranges::forward_range>); +static_assert(std::ranges::input_range>); +static_assert(std::ranges::view>); diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.default.pass.cpp new file mode 100644 index 00000000000000..0adb29cb461544 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.default.pass.cpp @@ -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 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// sentinel() = default; + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +constexpr bool test() { + using Sent = std::ranges::sentinel_t, IntComparableWith>>>; + using Iter = std::ranges::iterator_t, IntComparableWith>>>; + assert(Sent() == Iter()); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.pass.cpp new file mode 100644 index 00000000000000..ebb273873e2bcf --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// constexpr explicit sentinel(Bound bound); + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +constexpr bool test() { + { + using Sent = std::ranges::sentinel_t>>; + using Iter = std::ranges::iterator_t>>; + auto sent = Sent(IntSentinelWith(42)); + assert(sent == Iter(42)); + } + { + using Sent = std::ranges::sentinel_t>>; + using Iter = std::ranges::iterator_t>>; + auto sent = Sent(IntSentinelWith(SomeInt(42))); + assert(sent == Iter(SomeInt(42))); + } + { + using Sent = std::ranges::sentinel_t>>; + static_assert(!std::is_convertible_v>); + static_assert( std::is_constructible_v>); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/eq.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/eq.pass.cpp new file mode 100644 index 00000000000000..b4b9d01fabd1aa --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/eq.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// friend constexpr bool operator==(const iterator& x, const sentinel& y); + +#include +#include + +#include "test_macros.h" +#include "../types.h" + +constexpr bool test() { + { + const std::ranges::iota_view> io(0, IntComparableWith(10)); + auto iter = io.begin(); + auto sent = io.end(); + assert(iter != sent); + assert(iter + 10 == sent); + } + { + std::ranges::iota_view> io(0, IntComparableWith(10)); + auto iter = io.begin(); + auto sent = io.end(); + assert(iter != sent); + assert(iter + 10 == sent); + } + { + const std::ranges::iota_view io(SomeInt(0), IntComparableWith(SomeInt(10))); + auto iter = io.begin(); + auto sent = io.end(); + assert(iter != sent); + assert(iter + 10 == sent); + } + { + std::ranges::iota_view io(SomeInt(0), IntComparableWith(SomeInt(10))); + auto iter = io.begin(); + auto sent = io.end(); + assert(iter != sent); + assert(iter + 10 == sent); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/minus.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/minus.pass.cpp new file mode 100644 index 00000000000000..6fd02878ca6557 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/minus.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// friend constexpr iter_difference_t operator-(const iterator& x, const sentinel& y) +// requires sized_­sentinel_­for; +// friend constexpr iter_difference_t operator-(const sentinel& x, const iterator& y) +// requires sized_­sentinel_­for; + +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "../types.h" + +template +concept MinusInvocable = requires(std::ranges::iota_view> io) { + io.end() - io.begin(); +}; + +constexpr bool test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + auto outIter = random_access_iterator(buffer); + std::ranges::iota_view, IntSentinelWith>> io( + outIter, IntSentinelWith>(std::ranges::next(outIter, 8))); + auto iter = io.begin(); + auto sent = io.end(); + assert(iter - sent == -8); + assert(sent - iter == 8); + } + { + auto outIter = random_access_iterator(buffer); + const std::ranges::iota_view, IntSentinelWith>> io( + outIter, IntSentinelWith>(std::ranges::next(outIter, 8))); + const auto iter = io.begin(); + const auto sent = io.end(); + assert(iter - sent == -8); + assert(sent - iter == 8); + } + + { + // The minus operator requires that "W" is an input_or_output_iterator. + static_assert(!MinusInvocable); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp new file mode 100644 index 00000000000000..4491b0f60eabef --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/size.pass.cpp @@ -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 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// constexpr auto size() const requires see below; + +#include +#include +#include + +#include "test_macros.h" +#include "types.h" + +constexpr bool test() { + // Both are integer like and both are less than zero. + { + const std::ranges::iota_view io(-10, -5); + assert(io.size() == 5); + } + { + const std::ranges::iota_view io(-10, -10); + assert(io.size() == 0); + } + + // Both are integer like and "value_" is less than zero. + { + const std::ranges::iota_view io(-10, 10); + assert(io.size() == 20); + } + { +// TODO: this is invalid with the current implementation. We need to file an LWG issue to +// fix this. Essentially the issue is: An int's min and max are -2147483648 and 2147483647 +// which means the negated min cannot be represented as an integer; it needs to be cast to +// an unsigned type first. That seems to be what the +// to-unsigned-like(bound_) + to-unsigned-like(-value_)) +// part of https://eel.is/c++draft/range.iota#view-15 is doing, but I think it's doing it +// wrong. It should be to-unsigned-like(bound_) - to-unsigned-like(value_)) (cast to +// unsigned first). +// const std::ranges::iota_view io(std::numeric_limits::min(), std::numeric_limits::max()); +// assert(io.size() == (static_cast(std::numeric_limits::max()) * 2) + 1); + } + + // It is UB for "bound_" to be less than "value_" i.e.: iota_view io(10, -5). + + // Both are integer like and neither less than zero. + { + const std::ranges::iota_view io(10, 20); + assert(io.size() == 10); + } + { + const std::ranges::iota_view io(10, 10); + assert(io.size() == 0); + } + { + const std::ranges::iota_view io(0, 0); + assert(io.size() == 0); + } + { + const std::ranges::iota_view io(0, std::numeric_limits::max()); + assert(io.size() == std::numeric_limits::max()); + } + + // Neither are integer like. + { + const std::ranges::iota_view io(SomeInt(-20), SomeInt(-10)); + assert(io.size() == 10); + } + { + const std::ranges::iota_view io(SomeInt(-10), SomeInt(-10)); + assert(io.size() == 0); + } + { + const std::ranges::iota_view io(SomeInt(0), SomeInt(0)); + assert(io.size() == 0); + } + { + const std::ranges::iota_view io(SomeInt(10), SomeInt(20)); + assert(io.size() == 10); + } + { + const std::ranges::iota_view io(SomeInt(10), SomeInt(10)); + assert(io.size() == 0); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/type.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/type.compile.pass.cpp new file mode 100644 index 00000000000000..73c4a349194a2a --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/type.compile.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +#include + +// Test that we SFINAE away iota_view. + +template std::ranges::iota_view f(int); +template void f(...); + +void test() { + f(42); +} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/types.h b/libcxx/test/std/ranges/range.factories/range.iota.view/types.h new file mode 100644 index 00000000000000..a6eb1b4d537aab --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/types.h @@ -0,0 +1,212 @@ +//===----------------------------------------------------------------------===// +// +// 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_FACTORIES_RANGE_IOTA_VIEW_TYPES_H +#define TEST_STD_RANGES_RANGE_FACTORIES_RANGE_IOTA_VIEW_TYPES_H + +#include "test_macros.h" + +struct SomeInt { + using difference_type = int; + + int value_; + constexpr explicit SomeInt(int value = 0) : value_(value) {} + + auto operator<=>(const SomeInt&) const = default; + + friend constexpr SomeInt& operator+=(SomeInt &lhs, const SomeInt& rhs) { + lhs.value_ += rhs.value_; return lhs; + } + friend constexpr SomeInt& operator-=(SomeInt &lhs, const SomeInt& rhs) { + lhs.value_ -= rhs.value_; return lhs; + } + + friend constexpr SomeInt& operator+=(SomeInt &lhs, difference_type rhs) { + lhs.value_ += rhs; return lhs; + } + friend constexpr SomeInt& operator-=(SomeInt &lhs, difference_type rhs) { + lhs.value_ -= rhs; return lhs; + } + + friend constexpr SomeInt operator+(SomeInt lhs, SomeInt rhs) { + return SomeInt{lhs.value_ + rhs.value_}; + } + friend constexpr int operator-(SomeInt lhs, SomeInt rhs) { + return lhs.value_ - rhs.value_; + } + + friend constexpr SomeInt operator+(SomeInt lhs, difference_type rhs) { + return SomeInt{lhs.value_ + rhs}; + } + friend constexpr int operator-(SomeInt lhs, difference_type rhs) { + return lhs.value_ - rhs; + } + + friend constexpr SomeInt operator+(difference_type lhs, SomeInt rhs) { + return SomeInt{lhs + rhs.value_}; + } + friend constexpr int operator-(difference_type lhs, SomeInt rhs) { + return lhs - rhs.value_; + } + + constexpr SomeInt& operator++() { ++value_; return *this; } + constexpr SomeInt operator++(int) { auto tmp = *this; ++value_; return tmp; } + constexpr SomeInt& operator--() { --value_; return *this; } + constexpr SomeInt operator--(int) { auto tmp = *this; --value_; return tmp; } +}; + +template +struct IntComparableWith { + using difference_type = std::iter_difference_t; + + T value_; + constexpr explicit IntComparableWith(T value = T()) : value_(value) {} + + friend constexpr bool operator==(IntComparableWith lhs, IntComparableWith rhs) { + return lhs.value_ == rhs.value_; + } + friend constexpr bool operator==(IntComparableWith lhs, T rhs) { + return lhs.value_ == rhs; + } + friend constexpr bool operator==(T lhs, IntComparableWith rhs) { + return lhs == rhs.value_; + } + + friend constexpr IntComparableWith operator+(IntComparableWith lhs, IntComparableWith rhs) { + return IntComparableWith{lhs.value_ + rhs.value_}; + } + friend constexpr difference_type operator-(IntComparableWith lhs, IntComparableWith rhs) { + return lhs.value_ - rhs.value_; + } + + constexpr IntComparableWith& operator++() { ++value_; return *this; } + constexpr IntComparableWith operator++(int) { auto tmp = *this; ++value_; return tmp; } + constexpr IntComparableWith operator--() { --value_; return *this; } +}; + +template +struct IntSentinelWith { + using difference_type = std::iter_difference_t; + + T value_; + constexpr explicit IntSentinelWith(T value = T()) : value_(value) {} + + friend constexpr bool operator==(IntSentinelWith lhs, IntSentinelWith rhs) { + return lhs.value_ == rhs.value_; + } + friend constexpr bool operator==(IntSentinelWith lhs, T rhs) { + return lhs.value_ == rhs; + } + friend constexpr bool operator==(T lhs, IntSentinelWith rhs) { + return lhs == rhs.value_; + } + + friend constexpr IntSentinelWith operator+(IntSentinelWith lhs, IntSentinelWith rhs) { + return IntSentinelWith{lhs.value_ + rhs.value_}; + } + friend constexpr difference_type operator-(IntSentinelWith lhs, IntSentinelWith rhs) { + return lhs.value_ - rhs.value_; + } + friend constexpr difference_type operator-(IntSentinelWith lhs, T rhs) { + return lhs.value_ - rhs; + } + friend constexpr difference_type operator-(T lhs, IntSentinelWith rhs) { + return lhs - rhs.value_; + } + + constexpr IntSentinelWith& operator++() { ++value_; return *this; } + constexpr IntSentinelWith operator++(int) { auto tmp = *this; ++value_; return tmp; } + constexpr IntSentinelWith operator--() { --value_; return *this; } +}; + +struct NotIncrementable { + using difference_type = int; + + int value_; + constexpr explicit NotIncrementable(int value = 0) : value_(value) {} + + bool operator==(const NotIncrementable&) const = default; + + friend constexpr NotIncrementable& operator+=(NotIncrementable &lhs, const NotIncrementable& rhs) { + lhs.value_ += rhs.value_; return lhs; + } + friend constexpr NotIncrementable& operator-=(NotIncrementable &lhs, const NotIncrementable& rhs) { + lhs.value_ -= rhs.value_; return lhs; + } + + friend constexpr NotIncrementable operator+(NotIncrementable lhs, NotIncrementable rhs) { + return NotIncrementable{lhs.value_ + rhs.value_}; + } + friend constexpr int operator-(NotIncrementable lhs, NotIncrementable rhs) { + return lhs.value_ - rhs.value_; + } + + constexpr NotIncrementable& operator++() { ++value_; return *this; } + constexpr void operator++(int) { ++value_; } + constexpr NotIncrementable& operator--() { --value_; return *this; } +}; +static_assert(!std::incrementable); + +struct NotDecrementable { + using difference_type = int; + + int value_; + constexpr explicit NotDecrementable(int value = 0) : value_(value) {} + + bool operator==(const NotDecrementable&) const = default; + + friend constexpr NotDecrementable& operator+=(NotDecrementable &lhs, const NotDecrementable& rhs) { + lhs.value_ += rhs.value_; return lhs; + } + friend constexpr NotDecrementable& operator-=(NotDecrementable &lhs, const NotDecrementable& rhs) { + lhs.value_ -= rhs.value_; return lhs; + } + + friend constexpr NotDecrementable operator+(NotDecrementable lhs, NotDecrementable rhs) { + return NotDecrementable{lhs.value_ + rhs.value_}; + } + friend constexpr int operator-(NotDecrementable lhs, NotDecrementable rhs) { + return lhs.value_ - rhs.value_; + } + + constexpr NotDecrementable& operator++() { ++value_; return *this; } + constexpr void operator++(int) { ++value_; } +}; + +enum CtorKind { DefaultTo42, ValueCtor }; + +template +struct Int42 { + using difference_type = int; + + int value_; + constexpr explicit Int42(int value) : value_(value) {} + constexpr explicit Int42() requires (CK == DefaultTo42) + : value_(42) {} + + bool operator==(const Int42&) const = default; + + friend constexpr Int42& operator+=(Int42 &lhs, const Int42& rhs) { + lhs.value_ += rhs.value_; return lhs; + } + friend constexpr Int42& operator-=(Int42 &lhs, const Int42& rhs) { + lhs.value_ -= rhs.value_; return lhs; + } + + friend constexpr Int42 operator+(Int42 lhs, Int42 rhs) { + return Int42{lhs.value_ + rhs.value_}; + } + friend constexpr int operator-(Int42 lhs, Int42 rhs) { + return lhs.value_ - rhs.value_; + } + + constexpr Int42& operator++() { ++value_; return *this; } + constexpr void operator++(int) { ++value_; } +}; + +#endif // TEST_STD_RANGES_RANGE_FACTORIES_RANGE_IOTA_VIEW_TYPES_H diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp new file mode 100644 index 00000000000000..661285585095c9 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/views_iota.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// views::iota + +#include +#include +#include + +#include "test_macros.h" +#include "types.h" + +template +constexpr void testType(U u) { + // Test that this generally does the right thing. + // Test with only one argument. + { + assert(*std::views::iota(T(0)).begin() == T(0)); + } + { + const auto io = std::views::iota(T(10)); + assert(*io.begin() == T(10)); + } + // Test with two arguments. + { + assert(*std::views::iota(T(0), u).begin() == T(0)); + } + { + const auto io = std::views::iota(T(10), u); + assert(*io.begin() == T(10)); + } + // Test that we return the correct type. + { + ASSERT_SAME_TYPE(decltype(std::views::iota(T(10))), std::ranges::iota_view); + ASSERT_SAME_TYPE(decltype(std::views::iota(T(10), u)), std::ranges::iota_view); + } + // Test that this is semiregular. + // Note: we cannot test perfect forwarding because both T and U must be copyable. + { + static_assert(std::semiregular>); + } +} + +struct X {}; + +constexpr bool test() { + testType(SomeInt(10)); + testType(IntComparableWith(SomeInt(10))); + testType(IntComparableWith(10)); + testType(IntComparableWith(10)); + testType(IntComparableWith(10)); + testType(int(10)); + testType(unsigned(10)); + testType(IntComparableWith(10)); + testType(short(10)); + testType(IntComparableWith(10)); + testType(IntComparableWith(10)); + + { + static_assert( std::is_invocable_v); + static_assert(!std::is_invocable_v); + static_assert( std::is_invocable_v); + static_assert(!std::is_invocable_v); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +}