diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv --- a/libcxx/docs/Status/RangesAlgorithms.csv +++ b/libcxx/docs/Status/RangesAlgorithms.csv @@ -36,10 +36,10 @@ Read-only,is_permutation,Not assigned,n/a,Not started Read-only,for_each,Not assigned,n/a,Not started Read-only,for_each_n,Not assigned,n/a,Not started -Write,copy,Not assigned,n/a,Not started -Write,copy_if,Not assigned,n/a,Not started -Write,copy_n,Not assigned,n/a,Not started -Write,copy_backward,Not assigned,n/a,Not started +Write,copy,Nikolas Klauser,`D122982 `_,✅ +Write,copy_if,Nikolas Klauser,`D122982 `_,✅ +Write,copy_n,Nikolas Klauser,`D122982 `_,✅ +Write,copy_backward,Nikolas Klauser,`D122982 `_,✅ Write,move,Not assigned,n/a,Not started Write,move_backward,Not assigned,n/a,Not started Write,fill,Not assigned,n/a,Not started diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -66,6 +66,10 @@ __algorithm/pop_heap.h __algorithm/prev_permutation.h __algorithm/push_heap.h + __algorithm/ranges_copy.h + __algorithm/ranges_copy_backward.h + __algorithm/ranges_copy_if.h + __algorithm/ranges_copy_n.h __algorithm/ranges_find.h __algorithm/ranges_find_if.h __algorithm/ranges_find_if_not.h diff --git a/libcxx/include/__algorithm/copy.h b/libcxx/include/__algorithm/copy.h --- a/libcxx/include/__algorithm/copy.h +++ b/libcxx/include/__algorithm/copy.h @@ -12,6 +12,8 @@ #include <__algorithm/unwrap_iter.h> #include <__config> #include <__iterator/iterator_traits.h> +#include <__utility/move.h> +#include <__utility/pair.h> #include #include @@ -23,53 +25,55 @@ // copy -template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 -_OutputIterator -__copy_constexpr(_InputIterator __first, _InputIterator __last, _OutputIterator __result) -{ - for (; __first != __last; ++__first, (void) ++__result) - *__result = *__first; - return __result; +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 +pair<_InIter, _OutIter> __copy_impl(_InIter __first, _Sent __last, _OutIter __result) { + while (__first != __last) { + *__result = *__first; + ++__first; + ++__result; + } + return pair<_InIter, _OutIter>(std::move(__first), std::move(__result)); } -template -inline _LIBCPP_INLINE_VISIBILITY -_OutputIterator -__copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) -{ - return _VSTD::__copy_constexpr(__first, __last, __result); +template ::value && is_trivially_copy_assignable<_ValueT>::value> > +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 +pair<_ValueT*, _ValueT*> __copy_impl(_ValueT* __first, _ValueT* __last, _ValueT* __result) { + if (__libcpp_is_constant_evaluated() +#ifndef _LIBCPP_COMPILER_GCC + && !is_trivially_copyable<_ValueT>::value +#endif + ) + return std::__copy_impl<_ValueT*, _ValueT*, _ValueT*>(__first, __last, __result); + const size_t __n = static_cast(__last - __first); + if (__n > 0) + __builtin_memmove(__result, __first, __n * sizeof(_ValueT)); + return pair<_ValueT*, _ValueT*>(__first + __n, __result + __n); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 +pair<_InIter, _OutIter> __copy(_InIter __first, _Sent __last, _OutIter __result) { + auto __ret = std::__copy_impl(std::move(__first), std::move(__last), std::move(__result)); + return pair<_InIter, _OutIter>(std::move(__ret.first), std::move(__ret.second)); } -template -inline _LIBCPP_INLINE_VISIBILITY -typename enable_if -< - is_same::type, _Up>::value && - is_trivially_copy_assignable<_Up>::value, - _Up* ->::type -__copy(_Tp* __first, _Tp* __last, _Up* __result) -{ - const size_t __n = static_cast(__last - __first); - if (__n > 0) - _VSTD::memmove(__result, __first, __n * sizeof(_Up)); - return __result + __n; +template ::value + && is_copy_constructible<_Sent>::value + && is_copy_constructible<_OutIter>::value> > +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 +pair<_InIter, _OutIter> __copy(_InIter __first, _Sent __last, _OutIter __result) { + auto __ret = std::__copy_impl(std::__unwrap_iter(__first), std::__unwrap_iter(__last), std::__unwrap_iter(__result)); + return pair<_InIter, _OutIter>(std::__rewrap_iter(__first, __ret.first), std::__rewrap_iter(__result, __ret.second)); } template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator -copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) -{ - if (__libcpp_is_constant_evaluated()) { - return _VSTD::__copy_constexpr(__first, __last, __result); - } else { - return _VSTD::__rewrap_iter(__result, - _VSTD::__copy(_VSTD::__unwrap_iter(__first), - _VSTD::__unwrap_iter(__last), - _VSTD::__unwrap_iter(__result))); - } +copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { + return std::__copy(__first, __last, __result).second; } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/copy_backward.h b/libcxx/include/__algorithm/copy_backward.h --- a/libcxx/include/__algorithm/copy_backward.h +++ b/libcxx/include/__algorithm/copy_backward.h @@ -9,9 +9,11 @@ #ifndef _LIBCPP___ALGORITHM_COPY_BACKWARD_H #define _LIBCPP___ALGORITHM_COPY_BACKWARD_H +#include <__algorithm/copy.h> #include <__algorithm/unwrap_iter.h> #include <__config> #include <__iterator/iterator_traits.h> +#include <__iterator/reverse_iterator.h> #include #include @@ -21,57 +23,38 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 -_OutputIterator -__copy_backward_constexpr(_BidirectionalIterator __first, _BidirectionalIterator __last, _OutputIterator __result) -{ - while (__first != __last) - *--__result = *--__last; - return __result; +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 +pair<_Iter1, _Iter2> __copy_backward_impl(_Iter1 __first, _Sent1 __last, _Iter2 __result) { + auto __ret = std::__copy(reverse_iterator<_Sent1>(__last), + reverse_iterator<_Iter1>(__first), + reverse_iterator<_Iter2>(__result)); + return pair<_Iter1, _Iter2>(__ret.first.base(), __ret.second.base()); } -template -inline _LIBCPP_INLINE_VISIBILITY -_OutputIterator -__copy_backward(_BidirectionalIterator __first, _BidirectionalIterator __last, _OutputIterator __result) -{ - return _VSTD::__copy_backward_constexpr(__first, __last, __result); +template ::value && is_trivially_copy_assignable<_ValueT>::value> > +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 +pair<_ValueT*, _ValueT*> __copy_backward_impl(_ValueT* __first, _ValueT* __last, _ValueT* __result) { + auto __distance = __last - __first; + std::__copy(__first, __last, __result - __distance); + return pair<_ValueT*, _ValueT*>(__first, __result - __distance); } -template -inline _LIBCPP_INLINE_VISIBILITY -typename enable_if -< - is_same::type, _Up>::value && - is_trivially_copy_assignable<_Up>::value, - _Up* ->::type -__copy_backward(_Tp* __first, _Tp* __last, _Up* __result) -{ - const size_t __n = static_cast(__last - __first); - if (__n > 0) - { - __result -= __n; - _VSTD::memmove(__result, __first, __n * sizeof(_Up)); - } - return __result; +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 +pair<_Iter1, _Iter2> __copy_backward(_Iter1 __first, _Sent1 __last, _Iter2 __result) { + auto __ret = std::__copy_backward_impl(std::__unwrap_iter(__first), + std::__unwrap_iter(__last), + std::__unwrap_iter(__result)); + return pair<_Iter1, _Iter2>(std::__rewrap_iter(__first, __ret.first), std::__rewrap_iter(__result, __ret.second)); } template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _BidirectionalIterator2 -copy_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, - _BidirectionalIterator2 __result) -{ - if (__libcpp_is_constant_evaluated()) { - return _VSTD::__copy_backward_constexpr(__first, __last, __result); - } else { - return _VSTD::__rewrap_iter(__result, - _VSTD::__copy_backward(_VSTD::__unwrap_iter(__first), - _VSTD::__unwrap_iter(__last), - _VSTD::__unwrap_iter(__result))); - } +copy_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, _BidirectionalIterator2 __result) { + return std::__copy_backward(__first, __last, __result).second; } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/ranges_copy.h b/libcxx/include/__algorithm/ranges_copy.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__algorithm/ranges_copy.h @@ -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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_COPY_H +#define _LIBCPP___ALGORITHM_RANGES_COPY_H + +#include <__algorithm/copy.h> +#include <__algorithm/in_out_result.h> +#include <__config> +#include <__functional/identity.h> +#include <__iterator/concepts.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using copy_result = in_out_result<_Ip, _Op>; + +namespace __copy { +struct __fn { + + template _Sent, weakly_incrementable _OutIter> + requires indirectly_copyable<_InIter, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr + copy_result<_InIter, _OutIter> operator()(_InIter __first, _Sent __last, _OutIter __result) const { + auto __ret = std::__copy(std::move(__first), std::move(__last), std::move(__result)); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template + requires indirectly_copyable, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr + copy_result, _OutIter> operator()(_Range&& __r, _OutIter __result) const { + auto __ret = std::__copy(ranges::begin(__r), ranges::end(__r), std::move(__result)); + return {std::move(__ret.first), std::move(__ret.second)}; + } +}; +} // namespace __copy + +inline namespace __cpo { + inline constexpr auto copy = __copy::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + +#endif // _LIBCPP___ALGORITHM_RANGES_COPY_H diff --git a/libcxx/include/__algorithm/ranges_copy_backward.h b/libcxx/include/__algorithm/ranges_copy_backward.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__algorithm/ranges_copy_backward.h @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// 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___ALGORITHM_RANGES_COPY_BACKWARD_H +#define _LIBCPP___ALGORITHM_RANGES_COPY_BACKWARD_H + +#include <__algorithm/copy_backward.h> +#include <__algorithm/in_out_result.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/reverse_iterator.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using copy_backward_result = in_out_result<_Ip, _Op>; + +namespace __copy_backward { +struct __fn { + + template _S1, bidirectional_iterator _I2> + requires indirectly_copyable<_I1, _I2> + _LIBCPP_HIDE_FROM_ABI constexpr + copy_backward_result<_I1, _I2> operator()(_I1 __first, _S1 __last, _I2 __result) const { + auto __ret = std::__copy_backward(__first, __last, __result); + return {__ret.first, __ret.second}; + } + + template + requires indirectly_copyable, _Ip> + _LIBCPP_HIDE_FROM_ABI constexpr + copy_backward_result, _Ip> operator()(_Rp&& __r, _Ip __result) const { + auto __ret = std::__copy_backward(ranges::begin(__r), + ranges::end(__r), + __result); + return {__ret.first, __ret.second}; + } +}; +} // namespace __copy_backward + +inline namespace __cpo { + inline constexpr auto copy_backward = __copy_backward::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + +#endif // _LIBCPP___ALGORITHM_RANGES_COPY_BACKWARD_H diff --git a/libcxx/include/__algorithm/ranges_copy_if.h b/libcxx/include/__algorithm/ranges_copy_if.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__algorithm/ranges_copy_if.h @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// 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___ALGORITHM_RANGES_COPY_IF_H +#define _LIBCPP___ALGORITHM_RANGES_COPY_IF_H + +#include <__algorithm/in_out_result.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using copy_if_result = in_out_result<_Ip, _Op>; + +namespace __copy_if { +struct __fn { + + template + _LIBCPP_HIDE_FROM_ABI static constexpr + copy_if_result <_InIter, _OutIter> + __go(_InIter __first, _Sent __last, _OutIter __result, _Pred& __pred, _Proj& __proj) { + for (; __first != __last; ++__first) { + if (std::invoke(__pred, std::invoke(__proj, *__first))) { + *__result = *__first; + ++__result; + } + } + return {std::move(__first), std::move(__result)}; + } + + template _Sent, weakly_incrementable _OutIter, class _Proj = identity, + indirect_unary_predicate> _Pred> + requires indirectly_copyable<_Iter, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr + copy_if_result<_Iter, _OutIter> + operator()(_Iter __first, _Sent __last, _OutIter __result, _Pred __pred, _Proj __proj = {}) const { + return __go(std::move(__first), std::move(__last), std::move(__result), __pred, __proj); + } + + template , _Proj>> _Pred> + requires indirectly_copyable, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr + copy_if_result, _OutIter> + operator()(_Range&& __r, _OutIter __result, _Pred __pred, _Proj __proj = {}) const { + return __go(ranges::begin(__r), ranges::end(__r), std::move(__result), __pred, __proj); + } +}; +} // namespace __copy_if + +inline namespace __cpo { + inline constexpr auto copy_if = __copy_if::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + +#endif // _LIBCPP___ALGORITHM_RANGES_COPY_IF_H diff --git a/libcxx/include/__algorithm/ranges_copy_n.h b/libcxx/include/__algorithm/ranges_copy_n.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__algorithm/ranges_copy_n.h @@ -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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_COPY_N_H +#define _LIBCPP___ALGORITHM_RANGES_COPY_N_H + +#include <__algorithm/copy.h> +#include <__algorithm/in_out_result.h> +#include <__algorithm/ranges_copy.h> +#include <__config> +#include <__functional/identity.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/unreachable_sentinel.h> +#include <__iterator/wrap_iter.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + +namespace ranges { + +template +using copy_n_result = in_out_result<_Ip, _Op>; + +namespace __copy_n { +struct __fn { + + template + _LIBCPP_HIDE_FROM_ABI constexpr static + copy_n_result<_InIter, _OutIter> __go(_InIter __first, _DiffType __n, _OutIter __result) { + while (__n != 0) { + *__result = *__first; + ++__first; + ++__result; + --__n; + } + return {std::move(__first), std::move(__result)}; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr static + copy_n_result<_InIter, _OutIter> __go(_InIter __first, _DiffType __n, _OutIter __result) { + auto __ret = std::__copy(__first, __first + __n, __result); + return {__ret.first, __ret.second}; + } + + template + requires indirectly_copyable<_Ip, _Op> + _LIBCPP_HIDE_FROM_ABI constexpr + copy_n_result<_Ip, _Op> operator()(_Ip __first, iter_difference_t<_Ip> __n, _Op __result) const { + return __go(std::move(__first), __n, std::move(__result)); + } +}; +} // namespace __copy_n + +inline namespace __cpo { + inline constexpr auto copy_n = __copy_n::__fn{}; +} // namespace __cpo +} // namespace ranges + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_RANGES_COPY_N_H diff --git a/libcxx/include/__algorithm/unwrap_iter.h b/libcxx/include/__algorithm/unwrap_iter.h --- a/libcxx/include/__algorithm/unwrap_iter.h +++ b/libcxx/include/__algorithm/unwrap_iter.h @@ -64,14 +64,14 @@ } template -_LIBCPP_HIDE_FROM_ABI +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _OrigIter __rewrap_iter(_OrigIter, _OrigIter __result) { return __result; } template -_LIBCPP_HIDE_FROM_ABI +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _OrigIter __rewrap_iter(_OrigIter __first, _UnwrappedIter __result) { // Precondition: __result is reachable from __first diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -83,6 +83,31 @@ indirect_unary_predicate, Proj>> Pred> constexpr borrowed_iterator_t find_if_not(R&& r, Pred pred, Proj proj = {}); // since C++20 + + template S, weakly_incrementable O> + requires indirectly_copyable + constexpr ranges::copy_result ranges::copy(I first, S last, O result); // since C++20 + + template + requires indirectly_copyable, O> + constexpr ranges::copy_result, O> ranges::copy(R&& r, O result); // since C++20 + + template + requires indirectly_copyable + constexpr ranges::copy_n_result + ranges::copy_n(I first, iter_difference_t n, O result); // since C++20 + + template S, weakly_incrementable O, class Proj = identity, + indirect_unary_predicate> Pred> + requires indirectly_copyable + constexpr ranges::copy_if_result + ranges::copy_if(I first, S last, O result, Pred pred, Proj proj = {}); // since C++20 + + template, Proj>> Pred> + requires indirectly_copyable, O> + constexpr ranges::copy_if_result, O> + ranges::copy_if(R&& r, O result, Pred pred, Proj proj = {}); // since C++20 } template @@ -802,6 +827,10 @@ #include <__algorithm/pop_heap.h> #include <__algorithm/prev_permutation.h> #include <__algorithm/push_heap.h> +#include <__algorithm/ranges_copy.h> +#include <__algorithm/ranges_copy_backward.h> +#include <__algorithm/ranges_copy_if.h> +#include <__algorithm/ranges_copy_n.h> #include <__algorithm/ranges_find.h> #include <__algorithm/ranges_find_if.h> #include <__algorithm/ranges_find_if_not.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -294,6 +294,10 @@ module pop_heap { private header "__algorithm/pop_heap.h" } module prev_permutation { private header "__algorithm/prev_permutation.h" } module push_heap { private header "__algorithm/push_heap.h" } + module ranges_copy { private header "__algorithm/ranges_copy.h" } + module ranges_copy_backward { private header "__algorithm/ranges_copy_backward.h" } + module ranges_copy_if { private header "__algorithm/ranges_copy_if.h" } + module ranges_copy_n { private header "__algorithm/ranges_copy_n.h" } module ranges_find { private header "__algorithm/ranges_find.h" } module ranges_find_if { private header "__algorithm/ranges_find_if.h" } module ranges_find_if_not { private header "__algorithm/ranges_find_if_not.h" } diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/algorithm/ranges_copy.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/algorithm/ranges_copy.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/algorithm/ranges_copy.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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: '__algorithm/ranges_copy.h'}} +#include <__algorithm/ranges_copy.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/algorithm/ranges_copy_backward.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/algorithm/ranges_copy_backward.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/algorithm/ranges_copy_backward.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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: '__algorithm/ranges_copy_backward.h'}} +#include <__algorithm/ranges_copy_backward.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/algorithm/ranges_copy_if.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/algorithm/ranges_copy_if.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/algorithm/ranges_copy_if.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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: '__algorithm/ranges_copy_if.h'}} +#include <__algorithm/ranges_copy_if.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/algorithm/ranges_copy_n.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/algorithm/ranges_copy_n.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/algorithm/ranges_copy_n.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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: '__algorithm/ranges_copy_n.h'}} +#include <__algorithm/ranges_copy_n.h> diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp @@ -0,0 +1,208 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// template S, weakly_incrementable O> +// requires indirectly_copyable +// constexpr ranges::copy_result ranges::copy(I first, S last, O result); +// template +// requires indirectly_copyable, O> +// constexpr ranges::copy_result, O> ranges::copy(R&& r, O result); + +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "test_iterators.h" + +template > +concept HasCopyIt = requires(In in, Sent sent, Out out) { std::ranges::copy(in, sent, out); }; + +static_assert(HasCopyIt); +static_assert(!HasCopyIt); +static_assert(!HasCopyIt); +static_assert(!HasCopyIt); +static_assert(!HasCopyIt); +struct NotIndirectlyCopyable {}; +static_assert(!HasCopyIt); +static_assert(!HasCopyIt); +static_assert(!HasCopyIt); + +template +concept HasCopyR = requires(Range range, Out out) { std::ranges::copy(range, out); }; + +static_assert(HasCopyR, int*>); +static_assert(!HasCopyR); +static_assert(!HasCopyR); +static_assert(!HasCopyR); +static_assert(!HasCopyR); +static_assert(!HasCopyR, int*>); +static_assert(!HasCopyR); +static_assert(!HasCopyR); + +static_assert(std::is_same_v, std::ranges::in_out_result>); + +template +constexpr void test_iterators() { + { // simple test + { + std::array in {1, 2, 3, 4}; + std::array out; + std::same_as> auto ret = + std::ranges::copy(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); + assert(in == out); + assert(base(ret.in) == in.data() + in.size()); + assert(base(ret.out) == out.data() + out.size()); + } + { + std::array in {1, 2, 3, 4}; + std::array out; + auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); + std::same_as> auto ret = std::ranges::copy(range, Out(out.data())); + assert(in == out); + assert(base(ret.in) == in.data() + in.size()); + assert(base(ret.out) == out.data() + out.size()); + } + } + + { // check that an empty range works + { + std::array in; + std::array out; + auto ret = std::ranges::copy(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); + assert(base(ret.in) == in.data()); + assert(base(ret.out) == out.data()); + } + { + std::array in; + std::array out; + auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); + auto ret = std::ranges::copy(range, Out(out.data())); + assert(base(ret.in) == in.data()); + assert(base(ret.out) == out.data()); + } + } +} + +template +constexpr void test_in_iterators() { + test_iterators, Out, sentinel_wrapper>>(); + test_iterators, Out>(); + test_iterators, Out>(); + test_iterators, Out>(); + test_iterators, Out>(); +} + +constexpr bool test() { + test_in_iterators>(); + test_in_iterators>(); + test_in_iterators>(); + test_in_iterators>(); + test_in_iterators>(); + + { // check that ranges::dangling is returned + std::array out; + std::same_as> auto ret = + std::ranges::copy(std::array {1, 2, 3, 4}, out.data()); + assert(ret.out == out.data() + 4); + assert((out == std::array{1, 2, 3, 4})); + } + + { // check that an iterator is returned with a borrowing range + std::array in {1, 2, 3, 4}; + std::array out; + std::same_as> auto ret = std::ranges::copy(std::views::all(in), out.data()); + assert(ret.in == in.data() + 4); + assert(ret.out == out.data() + 4); + assert(in == out); + } + + { // check that every element is copied exactly once + struct CopyOnce { + bool copied = false; + constexpr CopyOnce() = default; + constexpr CopyOnce(const CopyOnce& other) = delete; + constexpr CopyOnce& operator=(const CopyOnce& other) { + assert(!other.copied); + copied = true; + return *this; + } + }; + { + std::array in {}; + std::array out {}; + auto ret = std::ranges::copy(in.begin(), in.end(), out.begin()); + assert(ret.in == in.end()); + assert(ret.out == out.end()); + assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; })); + } + { + std::array in {}; + std::array out {}; + auto ret = std::ranges::copy(in, out.begin()); + assert(ret.in == in.end()); + assert(ret.out == out.end()); + assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; })); + } + } + + { // check that the range is copied backwards + struct OnlyForwardsCopyable { + OnlyForwardsCopyable* next = nullptr; + bool canCopy = false; + OnlyForwardsCopyable() = default; + constexpr OnlyForwardsCopyable& operator=(const OnlyForwardsCopyable&) { + assert(canCopy); + if (next != nullptr) + next->canCopy = true; + return *this; + } + }; + { + std::array in {}; + std::array out {}; + out[0].next = &out[1]; + out[1].next = &out[2]; + out[0].canCopy = true; + auto ret = std::ranges::copy(in, out.begin()); + assert(ret.in == in.end()); + assert(ret.out == out.end()); + assert(out[0].canCopy); + assert(out[1].canCopy); + assert(out[2].canCopy); + } + { + std::array in {}; + std::array out {}; + out[0].next = &out[1]; + out[1].next = &out[2]; + out[0].canCopy = true; + auto ret = std::ranges::copy(in.begin(), in.end(), out.begin()); + assert(ret.in == in.end()); + assert(ret.out == out.end()); + assert(out[0].canCopy); + assert(out[1].canCopy); + assert(out[2].canCopy); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp @@ -0,0 +1,200 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "test_iterators.h" + +template > +concept HasCopyIt = requires(In in, Sent sent, Out out) { std::ranges::copy_backward(in, sent, out); }; + +static_assert(HasCopyIt); +static_assert(!HasCopyIt); +static_assert(!HasCopyIt); +static_assert(!HasCopyIt); +static_assert(!HasCopyIt); +struct NotIndirectlyCopyable {}; +static_assert(!HasCopyIt); +static_assert(!HasCopyIt); +static_assert(!HasCopyIt); + +template +concept HasCopyR = requires(Range range, Out out) { std::ranges::copy_backward(range, out); }; + +static_assert(HasCopyR, int*>); +static_assert(!HasCopyR); +static_assert(!HasCopyR); +static_assert(!HasCopyR); +static_assert(!HasCopyR); +static_assert(!HasCopyR, int*>); +static_assert(!HasCopyR); +static_assert(!HasCopyR); + +static_assert(std::is_same_v, std::ranges::in_out_result>); + +template +constexpr void test_iterators() { + { // simple test + { + std::array in {1, 2, 3, 4}; + std::array out; + std::same_as> auto ret = + std::ranges::copy_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size())); + assert(in == out); + assert(base(ret.in) == in.data()); + assert(base(ret.out) == out.data()); + } + { + std::array in {1, 2, 3, 4}; + std::array out; + auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); + std::same_as> auto ret = + std::ranges::copy_backward(range, Out(out.data() + out.size())); + assert(in == out); + assert(base(ret.in) == in.data()); + assert(base(ret.out) == out.data()); + } + } + + { // check that an empty range works + { + std::array in; + std::array out; + auto ret = + std::ranges::copy_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size())); + assert(base(ret.in) == in.data()); + assert(base(ret.out) == out.data()); + } + { + std::array in; + std::array out; + auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); + auto ret = std::ranges::copy_backward(range, Out(out.data())); + assert(base(ret.in) == in.data()); + assert(base(ret.out) == out.data()); + } + } +} + +template +constexpr void test_in_iterators() { + test_iterators, Out>(); + test_iterators, Out>(); + test_iterators, Out>(); +} + +constexpr bool test() { + test_in_iterators>(); + test_in_iterators>(); + test_in_iterators>(); + + { // check that ranges::dangling is returned + std::array out; + std::same_as> auto ret = + std::ranges::copy_backward(std::array {1, 2, 3, 4}, out.data() + out.size()); + assert(ret.out == out.data()); + assert((out == std::array{1, 2, 3, 4})); + } + + { // check that an iterator is returned with a borrowing range + std::array in {1, 2, 3, 4}; + std::array out; + std::same_as> auto ret = + std::ranges::copy_backward(std::views::all(in), out.data() + out.size()); + assert(ret.in == in.data()); + assert(ret.out == out.data()); + assert(in == out); + } + + { // check that every element is copied exactly once + struct CopyOnce { + bool copied = false; + constexpr CopyOnce() = default; + constexpr CopyOnce(const CopyOnce& other) = delete; + constexpr CopyOnce& operator=(const CopyOnce& other) { + assert(!other.copied); + copied = true; + return *this; + } + }; + { + std::array in {}; + std::array out {}; + auto ret = std::ranges::copy_backward(in.begin(), in.end(), out.end()); + assert(ret.in == in.begin()); + assert(ret.out == out.begin()); + assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; })); + } + { + std::array in {}; + std::array out {}; + auto ret = std::ranges::copy_backward(in, out.end()); + assert(ret.in == in.begin()); + assert(ret.out == out.begin()); + assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; })); + } + } + + { // check that the range is copied backwards + struct OnlyBackwardsCopyable { + OnlyBackwardsCopyable* next = nullptr; + bool canCopy = false; + OnlyBackwardsCopyable() = default; + constexpr OnlyBackwardsCopyable& operator=(const OnlyBackwardsCopyable&) { + assert(canCopy); + if (next != nullptr) + next->canCopy = true; + return *this; + } + }; + { + std::array in {}; + std::array out {}; + out[1].next = &out[0]; + out[2].next = &out[1]; + out[2].canCopy = true; + auto ret = std::ranges::copy_backward(in, out.end()); + assert(ret.in == in.begin()); + assert(ret.out == out.begin()); + assert(out[0].canCopy); + assert(out[1].canCopy); + assert(out[2].canCopy); + } + { + std::array in {}; + std::array out {}; + out[1].next = &out[0]; + out[2].next = &out[1]; + out[2].canCopy = true; + auto ret = std::ranges::copy_backward(in.begin(), in.end(), out.end()); + assert(ret.in == in.begin()); + assert(ret.out == out.begin()); + assert(out[0].canCopy); + assert(out[1].canCopy); + assert(out[2].canCopy); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_if.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_if.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_if.pass.cpp @@ -0,0 +1,180 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// template S, weakly_incrementable O, class Proj = identity, +// indirect_unary_predicate> Pred> +// requires indirectly_copyable +// constexpr ranges::copy_if_result +// ranges::copy_if(I first, S last, O result, Pred pred, Proj proj = {}); +// template, Proj>> Pred> +// requires indirectly_copyable, O> +// constexpr ranges::copy_if_result, O> +// ranges::copy_if(R&& r, O result, Pred pred, Proj proj = {}); + +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "test_iterators.h" + +struct Functor { + bool operator()(int); +}; + +template , class Func = Functor> +concept HasCopyIfIt = requires(In first, Sent last, Out result) { std::ranges::copy_if(first, last, result, Func{}); }; + +static_assert(HasCopyIfIt); +static_assert(!HasCopyIfIt); +static_assert(!HasCopyIfIt); +static_assert(!HasCopyIfIt); +static_assert(!HasCopyIfIt); +struct NotIndirectlyCopyable {}; +static_assert(!HasCopyIfIt); +static_assert(!HasCopyIfIt); +static_assert(!HasCopyIfIt); + +static_assert(!HasCopyIfIt); +static_assert(!HasCopyIfIt); + +template +concept HasCopyIfR = requires(Range range, Out out) { std::ranges::copy_if(range, out, Func{}); }; + +static_assert(HasCopyIfR, int*>); +static_assert(!HasCopyIfR); +static_assert(!HasCopyIfR); +static_assert(!HasCopyIfR); +static_assert(!HasCopyIfR); +static_assert(!HasCopyIfR, int*>); +static_assert(!HasCopyIfR); +static_assert(!HasCopyIfR); + +static_assert(std::is_same_v, std::ranges::in_out_result>); + +template +constexpr void test_iterators() { + { // simple test + { + std::array in = {1, 2, 3, 4}; + std::array out; + std::same_as> auto ret = + std::ranges::copy_if(In(in.data()), + Sent(In(in.data() + in.size())), + Out(out.data()), + [](int) { return true; }); + assert(in == out); + assert(base(ret.in) == in.data() + in.size()); + assert(base(ret.out) == out.data() + out.size()); + } + { + std::array in = {1, 2, 3, 4}; + std::array out; + auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); + std::same_as> auto ret = + std::ranges::copy_if(range, Out(out.data()), [](int) { return true; }); + assert(in == out); + assert(base(ret.in) == in.data() + in.size()); + assert(base(ret.out) == out.data() + out.size()); + } + } + + { // check that an empty range works + { + std::array in; + std::array out; + auto ret = std::ranges::copy_if(In(in.data()), Sent(In(in.data())), Out(out.data()), [](int) { return true; }); + assert(base(ret.in) == in.data()); + assert(base(ret.out) == out.data()); + } + { + std::array in; + std::array out; + auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data()))); + auto ret = std::ranges::copy_if(range, Out(out.data()), [](int) { return true; }); + assert(base(ret.in) == in.data()); + assert(base(ret.out) == out.data()); + } + } + + { // check that the predicate is used + { + std::array in = {4, 6, 87, 3}; + std::array out; + auto ret = std::ranges::copy_if(In(in.data()), + Sent(In(in.data() + in.size())), + Out(out.data()), + [](int i) { return i % 2 == 0; }); + assert((out == std::array{4, 6})); + assert(base(ret.in) == in.data() + in.size()); + assert(base(ret.out) == out.data() + out.size()); + } + { + std::array in = {4, 6, 87, 3}; + std::array out; + auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + 4))); + auto ret = std::ranges::copy_if(range, Out(out.data()), [](int i) { return i % 2 == 0; }); + assert((out == std::array{4, 6})); + assert(base(ret.in) == in.data() + in.size()); + assert(base(ret.out) == out.data() + out.size()); + } + } +} + +template +constexpr bool test_in_iterators() { + test_iterators, Out, sentinel_wrapper>>(); + test_iterators, Out, sentinel_wrapper>>(); + test_iterators, Out>(); + test_iterators, Out>(); + test_iterators, Out>(); + test_iterators, Out>(); + test_iterators(); + + return true; +} + +constexpr bool test() { + test_in_iterators>(); + test_in_iterators>(); + test_in_iterators>(); + test_in_iterators>(); + test_in_iterators>(); + test_in_iterators(); + + { // check that std::invoke is used + { + struct S { int val; int other; }; + std::array in = {{{4, 2}, {1, 3}, {3, 4}, {3, 5}}}; + std::array out; + auto ret = std::ranges::copy_if(in.begin(), in.end(), out.begin(), [](int i) { return i == 3; }, &S::val); + assert(ret.in == in.end()); + assert(ret.out == out.end()); + assert(out[0].val == 3); + assert(out[0].other == 4); + assert(out[1].val == 3); + assert(out[1].other == 5); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_n.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_n.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_n.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-has-no-incomplete-ranges + +// template +// requires indirectly_copyable +// constexpr ranges::copy_n_result +// ranges::copy_n(I first, iter_difference_t n, O result); + +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "test_iterators.h" + +template +concept HasCopyNIt = requires(In in, Count count, Out out) { std::ranges::copy_n(in, count, out); }; + +static_assert(HasCopyNIt); +static_assert(!HasCopyNIt); +static_assert(!HasCopyNIt); +static_assert(!HasCopyNIt); +static_assert(!HasCopyNIt); +struct NotIndirectlyCopyable {}; +static_assert(!HasCopyNIt); +static_assert(!HasCopyNIt); +static_assert(!HasCopyNIt); + +static_assert(std::is_same_v, std::ranges::in_out_result>); + +template +constexpr void test_iterators() { + { // simple test + std::array in {1, 2, 3, 4}; + std::array out; + std::same_as> auto ret = + std::ranges::copy_n(In(in.data()), in.size(), Out(out.data())); + assert(in == out); + assert(base(ret.in) == in.data() + in.size()); + assert(base(ret.out) == out.data() + out.size()); + } + + { // check that an empty range works + std::array in; + std::array out; + auto ret = std::ranges::copy_n(In(in.data()), in.size(), Out(out.begin())); + assert(base(ret.in) == in.data()); + assert(base(ret.out) == out.data()); + } +} + +template +constexpr void test_in_iterators() { + test_iterators, Out, sentinel_wrapper>>(); + test_iterators, Out>(); + test_iterators, Out>(); + test_iterators, Out>(); + test_iterators, Out>(); +} + +constexpr bool test() { + test_in_iterators>(); + test_in_iterators>(); + test_in_iterators>(); + test_in_iterators>(); + test_in_iterators>(); + + { // check that every element is copied exactly once + struct CopyOnce { + bool copied = false; + constexpr CopyOnce() = default; + constexpr CopyOnce(const CopyOnce& other) = delete; + constexpr CopyOnce& operator=(const CopyOnce& other) { + assert(!other.copied); + copied = true; + return *this; + } + }; + std::array in {}; + std::array out {}; + auto ret = std::ranges::copy_n(in.data(), in.size(), out.begin()); + assert(ret.in == in.end()); + assert(ret.out == out.end()); + assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; })); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/support/almost_satisfies_types.h b/libcxx/test/support/almost_satisfies_types.h --- a/libcxx/test/support/almost_satisfies_types.h +++ b/libcxx/test/support/almost_satisfies_types.h @@ -128,4 +128,15 @@ static_assert(std::semiregular); static_assert(!std::sentinel_for>); +class WeaklyIncrementableNotMovable { +public: + using difference_type = long; + WeaklyIncrementableNotMovable& operator++(); + void operator++(int); + WeaklyIncrementableNotMovable(const WeaklyIncrementableNotMovable&) = delete; +}; + +static_assert(!std::movable); +static_assert(!std::weakly_incrementable); + #endif // ALMOST_SATISFIES_TYPES_H