diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -838,6 +838,7 @@ __utility/cmp.h __utility/convert_to_integral.h __utility/declval.h + __utility/empty.h __utility/exception_guard.h __utility/exchange.h __utility/forward.h @@ -851,7 +852,6 @@ __utility/priority_tag.h __utility/rel_ops.h __utility/swap.h - __utility/terminate_on_exception.h __utility/to_underlying.h __utility/unreachable.h __variant/monostate.h diff --git a/libcxx/include/__algorithm/pstl_any_all_none_of.h b/libcxx/include/__algorithm/pstl_any_all_none_of.h --- a/libcxx/include/__algorithm/pstl_any_all_none_of.h +++ b/libcxx/include/__algorithm/pstl_any_all_none_of.h @@ -17,7 +17,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -35,19 +35,35 @@ class _Predicate, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool -any_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional __any_of( + _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_any_of), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { - return std::find_if(__policy, __g_first, __g_last, __g_pred) != __g_last; + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) -> optional { + auto __res = std::__find_if(__policy, __g_first, __g_last, __g_pred); + if (!__res) + return nullopt; + return *__res != __g_last; }, std::move(__first), std::move(__last), std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool +any_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__any_of(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + template void __pstl_all_of(); // declaration needed for the frontend dispatch below @@ -56,21 +72,37 @@ class _Pred, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool -all_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional +__all_of(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Pred&& __pred) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_all_of), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) { - return !std::any_of(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) { + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) -> optional { + auto __res = std::__any_of(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) { return !__g_pred(__value); }); + if (!__res) + return nullopt; + return !*__res; }, std::move(__first), std::move(__last), std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool +all_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__all_of(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + template void __pstl_none_of(); // declaration needed for the frontend dispatch below @@ -79,19 +111,35 @@ class _Pred, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool -none_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional +__none_of(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Pred&& __pred) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_none_of), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) { - return !std::any_of(__policy, __g_first, __g_last, __g_pred); + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) -> optional { + auto __res = std::__any_of(__policy, __g_first, __g_last, __g_pred); + if (!__res) + return nullopt; + return !*__res; }, std::move(__first), std::move(__last), std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool +none_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__none_of(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_backend.h b/libcxx/include/__algorithm/pstl_backend.h --- a/libcxx/include/__algorithm/pstl_backend.h +++ b/libcxx/include/__algorithm/pstl_backend.h @@ -27,23 +27,25 @@ A PSTL parallel backend is a tag type to which the following functions are associated, at minimum: template - void __pstl_for_each(_Backend, _ExecutionPolicy&&, _Iterator __first, _Iterator __last, _Func __f); + optional<__empty> __pstl_for_each(_Backend, _ExecutionPolicy&&, _Iterator __first, _Iterator __last, _Func __f); template - _Iterator __pstl_find_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); + optional<_Iterator> __pstl_find_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); template - void __pstl_stable_sort(_Backend, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp); + optional<__empty> + __pstl_stable_sort(_Backend, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp); template - _OutIterator __pstl_transform(_InIterator __first, _InIterator __last, _OutIterator __result, _UnaryOperation __op); + optional<_OutIterator> + __pstl_transform(_InIterator __first, _InIterator __last, _OutIterator __result, _UnaryOperation __op); template - _OutIterator __pstl_transform(_InIterator1 __first1, - _InIterator1 __last1, - _InIterator2 __first2, - _OutIterator __result, - _BinaryOperation __op); + optional<_OutIterator> __pstl_transform(_InIterator1 __first1, + _InIterator2 __first2, + _InIterator1 __last1, + _OutIterator __result, + _BinaryOperation __op); template - _Tp __pstl_transform_reduce(_Backend, - _Iterator1 __first1, - _Iterator1 __last1, - _Iterator2 __first2, - _Iterator2 __last2, - _Tp __init, - _BinaryOperation1 __reduce, - _BinaryOperation2 __transform); + optional<_Tp> __pstl_transform_reduce(_Backend, + _Iterator1 __first1, + _Iterator1 __last1, + _Iterator2 __first2, + _Iterator2 __last2, + _Tp __init, + _BinaryOperation1 __reduce, + _BinaryOperation2 __transform); template - _Tp __pstl_transform_reduce(_Backend, - _Iterator __first, - _Iterator __last, - _Tp __init, - _BinaryOperation __reduce, - _UnaryOperation __transform); + optional<_Tp> __pstl_transform_reduce(_Backend, + _Iterator __first, + _Iterator __last, + _Tp __init, + _BinaryOperation __reduce, + _UnaryOperation __transform); // TODO: Complete this list @@ -75,86 +77,95 @@ implemented, all the algorithms will eventually forward to the basis algorithms listed above: template - void __pstl_for_each_n(_Backend, _Iterator __first, _Size __n, _Func __f); + optional<__empty> __pstl_for_each_n(_Backend, _Iterator __first, _Size __n, _Func __f); template - bool __pstl_any_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); + optional __pstl_any_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); template - bool __pstl_all_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); + optional __pstl_all_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); template - bool __pstl_none_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); + optional __pstl_none_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred); template - _Iterator __pstl_find(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value); + optional<_Iterator> __pstl_find(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value); template - _Iterator __pstl_find_if_not(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); + optional<_Iterator> __pstl_find_if_not(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); template - void __pstl_fill(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value); + optional<__empty> __pstl_fill(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value); template - void __pstl_fill_n(_Backend, _Iterator __first, _SizeT __n, const _Tp& __value); + optional<__empty> __pstl_fill_n(_Backend, _Iterator __first, _SizeT __n, const _Tp& __value); template - void __pstl_generate(_Backend, _Iterator __first, _Iterator __last, _Generator __gen); + optional<__empty> __pstl_generate(_Backend, _Iterator __first, _Iterator __last, _Generator __gen); template - void __pstl_is_partitioned(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); + optional<__empty> __pstl_is_partitioned(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); template - void __pstl_generator_n(_Backend, _Iterator __first, _Size __n, _Generator __gen); + optional<__empty> __pstl_generator_n(_Backend, _Iterator __first, _Size __n, _Generator __gen); template - _OutIterator __pstl_merge(_Backend, - _Iterator1 __first1, - _Iterator1 __last1, - _Iterator2 __first2, - _Iterator2 __last2, - _OutIterator __result, - _Comp __comp); + optional<_OutIterator> __pstl_merge(_Backend, + _Iterator1 __first1, + _Iterator1 __last1, + _Iterator2 __first2, + _Iterator2 __last2, + _OutIterator __result, + _Comp __comp); template - _Tp __pstl_reduce(_Backend, _Iterator __first, _Iterator __last, _Tp __init, _BinaryOperation __op); + optional<_Tp> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last, _Tp __init, _BinaryOperation __op); temlate - __iter_value_type<_Iterator> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last); + optional<__iter_value_type<_Iterator>> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last); template - __iter_diff_t<_Iterator> __pstl_count(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value); + optional<__iter_diff_t<_Iterator>> __pstl_count(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value); template - __iter_diff_t<_Iterator> __pstl_count_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); + optional<__iter_diff_t<_Iterator>> __pstl_count_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred); template - void __pstl_replace(_Backend, _Iterator __first, _Iterator __last, const _Tp& __old_value, const _Tp& __new_value); + optional<__empty> + __pstl_replace(_Backend, _Iterator __first, _Iterator __last, const _Tp& __old_value, const _Tp& __new_value); template - void __pstl_replace_if(_Backend, _Iterator __first, _Iterator __last, _Pred __pred, const _Tp& __new_value); + optional<__empty> + __pstl_replace_if(_Backend, _Iterator __first, _Iterator __last, _Pred __pred, const _Tp& __new_value); template - void __pstl_replace_copy(_Backend, - _Iterator __first, - _Iterator __last, - _OutIterator __result, - const _Tp& __old_value, - const _Tp& __new_value); + optional<__empty> __pstl_replace_copy(_Backend, + _Iterator __first, + _Iterator __last, + _OutIterator __result, + const _Tp& __old_value, + const _Tp& __new_value); template - void __pstl_replace_copy_if(_Backend, - _Iterator __first, - _Iterator __last, - _OutIterator __result, - _Pred __pred, - const _Tp& __new_value); + optional<__empty> __pstl_replace_copy_if(_Backend, + _Iterator __first, + _Iterator __last, + _OutIterator __result, + _Pred __pred, + const _Tp& __new_value); template - void __pstl_sort(_Backend, _Iterator __first, _Iterator __last, _Comp __comp); + optional<__empty> __pstl_sort(_Backend, _Iterator __first, _Iterator __last, _Comp __comp); // TODO: Complete this list +Exception handling +================== + +PSTL backends are expected to report errors (i.e. failure to allocate) by returning a disengaged `optional` from their +implementation. Exceptions shouldn't be used to report an internal failure-to-allocate, since all exceptions are turned +into a program termination at the front-end level. When a backend returns a disengaged `optional` to the frontend, the +frontend will turn that into a call to `std::__throw_bad_alloc();` to report the internal failure to the user. */ template diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backend.h b/libcxx/include/__algorithm/pstl_backends/cpu_backend.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backend.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backend.h @@ -15,10 +15,11 @@ // _Functor takes a subrange for [__first, __last) that should be executed in serial template - void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func); + optional<__empty> __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func); template - _Tp __parallel_transform_reduce(_Iterator __first, _Iterator __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduction); + optional<_Tp> + __parallel_transform_reduce(_Iterator __first, _Iterator __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduction); // Cancel the execution of other jobs - they aren't needed anymore void __cancel_execution(); @@ -28,7 +29,7 @@ class _RandomAccessIterator3, class _Compare, class _LeafMerge> - void __parallel_merge( + optional __parallel_merge( _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2, @@ -44,6 +45,14 @@ _LeafSort __leaf_sort); TODO: Document the parallel backend + +Exception handling +================== + +CPU backends are expected to report errors (i.e. failure to allocate) by returning a disengaged `optional` from their +implementation. Exceptions shouldn't be used to report an internal failure-to-allocate, since all exceptions are turned +into a program termination at the front-end level. When a backend returns a disengaged `optional` to the frontend, the +frontend will turn that into a call to `std::__throw_bad_alloc();` to report the internal failure to the user. */ #include <__algorithm/pstl_backends/cpu_backends/any_of.h> diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h @@ -18,24 +18,30 @@ #include <__functional/operations.h> #include <__iterator/concepts.h> #include <__type_traits/is_execution_policy.h> +#include <__utility/move.h> #include <__utility/pair.h> -#include <__utility/terminate_on_exception.h> #include +#include #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template -_LIBCPP_HIDE_FROM_ABI bool __parallel_or(_Index __first, _Index __last, _Brick __f) { +_LIBCPP_HIDE_FROM_ABI optional __parallel_or(_Index __first, _Index __last, _Brick __f) { std::atomic __found(false); - __par_backend::__parallel_for(__first, __last, [__f, &__found](_Index __i, _Index __j) { + auto __ret = __par_backend::__parallel_for(__first, __last, [__f, &__found](_Index __i, _Index __j) { if (!__found.load(std::memory_order_relaxed) && __f(__i, __j)) { __found.store(true, std::memory_order_relaxed); __par_backend::__cancel_execution(); } }); - return __found; + if (!__ret) + return nullopt; + return static_cast(__found); } // TODO: check whether __simd_first() can be used here @@ -64,17 +70,17 @@ } template -_LIBCPP_HIDE_FROM_ABI bool +_LIBCPP_HIDE_FROM_ABI optional __pstl_any_of(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { - return std::__terminate_on_exception([&] { - return std::__parallel_or( - __first, __last, [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - return std::__pstl_any_of<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, __brick_first, __brick_last, __pred); - }); - }); + return std::__parallel_or( + __first, __last, [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + auto __res = std::__pstl_any_of<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __pred); + _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); + return *std::move(__res); + }); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { return std::__simd_or(__first, __last - __first, __pred); @@ -85,6 +91,8 @@ _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_ANY_OF_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h @@ -14,7 +14,8 @@ #include <__config> #include <__iterator/concepts.h> #include <__type_traits/is_execution_policy.h> -#include <__utility/terminate_on_exception.h> +#include <__utility/empty.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -34,22 +35,23 @@ } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI optional<__empty> __pstl_fill(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { - std::__terminate_on_exception([&] { - __par_backend::__parallel_for( - __first, __last, [&__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - std::__pstl_fill<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, __brick_first, __brick_last, __value); - }); - }); + return __par_backend::__parallel_for( + __first, __last, [&__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + [[maybe_unused]] auto __res = std::__pstl_fill<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __value); + _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); + }); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { std::__simd_fill_n(__first, __last - __first, __value); + return __empty{}; } else { std::fill(__first, __last, __value); + return __empty{}; } } diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h @@ -17,9 +17,10 @@ #include <__iterator/concepts.h> #include <__iterator/iterator_traits.h> #include <__type_traits/is_execution_policy.h> +#include <__utility/move.h> #include <__utility/pair.h> -#include <__utility/terminate_on_exception.h> #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -27,31 +28,37 @@ #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template -_LIBCPP_HIDE_FROM_ABI _Index +_LIBCPP_HIDE_FROM_ABI optional<_Index> __parallel_find(_Index __first, _Index __last, _Brick __f, _Compare __comp, bool __b_first) { typedef typename std::iterator_traits<_Index>::difference_type _DifferenceType; const _DifferenceType __n = __last - __first; _DifferenceType __initial_dist = __b_first ? __n : -1; std::atomic<_DifferenceType> __extremum(__initial_dist); // TODO: find out what is better here: parallel_for or parallel_reduce - __par_backend::__parallel_for(__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) { - // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of - // why using a shared variable scales fairly well in this situation. - if (__comp(__i - __first, __extremum)) { - _Index __res = __f(__i, __j); - // If not '__last' returned then we found what we want so put this to extremum - if (__res != __j) { - const _DifferenceType __k = __res - __first; - for (_DifferenceType __old = __extremum; __comp(__k, __old); __old = __extremum) { - __extremum.compare_exchange_weak(__old, __k); + auto __res = + __par_backend::__parallel_for(__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) { + // See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of + // why using a shared variable scales fairly well in this situation. + if (__comp(__i - __first, __extremum)) { + _Index __result = __f(__i, __j); + // If not '__last' returned then we found what we want so put this to extremum + if (__result != __j) { + const _DifferenceType __k = __result - __first; + for (_DifferenceType __old = __extremum; __comp(__k, __old); __old = __extremum) { + __extremum.compare_exchange_weak(__old, __k); + } + } } - } - } - }); - return __extremum != __initial_dist ? __first + __extremum : __last; + }); + if (!__res) + return nullopt; + return __extremum.load() != __initial_dist ? __first + __extremum.load() : __last; } template @@ -91,21 +98,21 @@ } template -_LIBCPP_HIDE_FROM_ABI _ForwardIterator +_LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator> __pstl_find_if(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { - return std::__terminate_on_exception([&] { - return std::__parallel_find( - __first, - __last, - [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - return std::__pstl_find_if<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, __brick_first, __brick_last, __pred); - }, - less<>{}, - true); - }); + return std::__parallel_find( + __first, + __last, + [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + auto __res = std::__pstl_find_if<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __pred); + _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); + return *std::move(__res); + }, + less<>{}, + true); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { using __diff_t = __iter_diff_t<_ForwardIterator>; @@ -119,6 +126,8 @@ _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_FIND_IF_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h @@ -14,7 +14,8 @@ #include <__config> #include <__iterator/concepts.h> #include <__type_traits/is_execution_policy.h> -#include <__utility/terminate_on_exception.h> +#include <__utility/empty.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -34,22 +35,23 @@ } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI optional<__empty> __pstl_for_each(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Functor __func) { if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { - std::__terminate_on_exception([&] { - std::__par_backend::__parallel_for( - __first, __last, [__func](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - std::__pstl_for_each<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, __brick_first, __brick_last, __func); - }); - }); + return std::__par_backend::__parallel_for( + __first, __last, [__func](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + [[maybe_unused]] auto __res = std::__pstl_for_each<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __func); + _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); + }); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { std::__simd_walk_1(__first, __last - __first, __func); + return __empty{}; } else { std::for_each(__first, __last, __func); + return __empty{}; } } diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h @@ -23,11 +23,13 @@ #include <__memory/construct_at.h> #include <__memory/unique_ptr.h> #include <__numeric/reduce.h> +#include <__utility/empty.h> +#include <__utility/exception_guard.h> #include <__utility/move.h> #include <__utility/pair.h> -#include <__utility/terminate_on_exception.h> #include #include +#include _LIBCPP_PUSH_MACROS #include <__undef_macros> @@ -61,8 +63,9 @@ [[__gnu__::__const__]] _LIBCPP_EXPORTED_FROM_ABI __chunk_partitions __partition_chunks(ptrdiff_t __size) noexcept; template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI optional<__empty> __dispatch_parallel_for(__chunk_partitions __partitions, _RandomAccessIterator __first, _Functor __func) { + // Perform the chunked execution. __libdispatch::__dispatch_apply(__partitions.__chunk_count_, [&](size_t __chunk) { auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_; auto __index = @@ -71,10 +74,12 @@ : (__chunk * __partitions.__chunk_size_) + (__partitions.__first_chunk_size_ - __partitions.__chunk_size_); __func(__first + __index, __first + __index + __this_chunk_size); }); + + return __empty{}; } template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func) { return __libdispatch::__dispatch_parallel_for( __libdispatch::__partition_chunks(__last - __first), std::move(__first), std::move(__func)); @@ -95,23 +100,23 @@ typename _RandomAccessIterator3, typename _Compare, typename _LeafMerge> -_LIBCPP_HIDE_FROM_ABI void __parallel_merge( +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_merge( _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _RandomAccessIterator3 __result, _Compare __comp, - _LeafMerge __leaf_merge) { + _LeafMerge __leaf_merge) noexcept { __chunk_partitions __partitions = __libdispatch::__partition_chunks(std::max(__last1 - __first1, __last2 - __first2)); if (__partitions.__chunk_count_ == 0) - return; + return __empty{}; if (__partitions.__chunk_count_ == 1) { __leaf_merge(__first1, __last1, __first2, __last2, __result, __comp); - return; + return __empty{}; } using __merge_range_t = __merge_range<_RandomAccessIterator1, _RandomAccessIterator2, _RandomAccessIterator3>; @@ -122,61 +127,76 @@ std::destroy_n(__ptr, __n_ranges); std::allocator<__merge_range_t>().deallocate(__ptr, __n_ranges); }; + unique_ptr<__merge_range_t[], decltype(__destroy)> __ranges( - std::allocator<__merge_range_t>().allocate(__n_ranges), __destroy); + [&]() -> __merge_range_t* { +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS + try { +# endif + return std::allocator<__merge_range_t>().allocate(__n_ranges); +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS + } catch (const std::bad_alloc&) { + return nullptr; + } +# endif + }(), + __destroy); + + if (!__ranges) + return nullopt; // TODO: Improve the case where the smaller range is merged into just a few (or even one) chunks of the larger case - std::__terminate_on_exception([&] { - __merge_range_t* __r = __ranges.get(); - std::__construct_at(__r++, __first1, __first2, __result); - - bool __iterate_first_range = __last1 - __first1 > __last2 - __first2; - - auto __compute_chunk = [&](size_t __chunk_size) -> __merge_range_t { - auto [__mid1, __mid2] = [&] { - if (__iterate_first_range) { - auto __m1 = __first1 + __chunk_size; - auto __m2 = std::lower_bound(__first2, __last2, __m1[-1], __comp); - return std::make_pair(__m1, __m2); - } else { - auto __m2 = __first2 + __chunk_size; - auto __m1 = std::lower_bound(__first1, __last1, __m2[-1], __comp); - return std::make_pair(__m1, __m2); - } - }(); + __merge_range_t* __r = __ranges.get(); + std::__construct_at(__r++, __first1, __first2, __result); - __result += (__mid1 - __first1) + (__mid2 - __first2); - __first1 = __mid1; - __first2 = __mid2; - return {std::move(__mid1), std::move(__mid2), __result}; - }; + bool __iterate_first_range = __last1 - __first1 > __last2 - __first2; - // handle first chunk - std::__construct_at(__r++, __compute_chunk(__partitions.__first_chunk_size_)); - - // handle 2 -> N - 1 chunks - for (ptrdiff_t __i = 0; __i != __partitions.__chunk_count_ - 2; ++__i) - std::__construct_at(__r++, __compute_chunk(__partitions.__chunk_size_)); - - // handle last chunk - std::__construct_at(__r, __last1, __last2, __result); - - __libdispatch::__dispatch_apply(__partitions.__chunk_count_, [&](size_t __index) { - auto __first_iters = __ranges[__index]; - auto __last_iters = __ranges[__index + 1]; - __leaf_merge( - __first_iters.__mid1_, - __last_iters.__mid1_, - __first_iters.__mid2_, - __last_iters.__mid2_, - __first_iters.__result_, - __comp); - }); + auto __compute_chunk = [&](size_t __chunk_size) -> __merge_range_t { + auto [__mid1, __mid2] = [&] { + if (__iterate_first_range) { + auto __m1 = __first1 + __chunk_size; + auto __m2 = std::lower_bound(__first2, __last2, __m1[-1], __comp); + return std::make_pair(__m1, __m2); + } else { + auto __m2 = __first2 + __chunk_size; + auto __m1 = std::lower_bound(__first1, __last1, __m2[-1], __comp); + return std::make_pair(__m1, __m2); + } + }(); + + __result += (__mid1 - __first1) + (__mid2 - __first2); + __first1 = __mid1; + __first2 = __mid2; + return {std::move(__mid1), std::move(__mid2), __result}; + }; + + // handle first chunk + std::__construct_at(__r++, __compute_chunk(__partitions.__first_chunk_size_)); + + // handle 2 -> N - 1 chunks + for (ptrdiff_t __i = 0; __i != __partitions.__chunk_count_ - 2; ++__i) + std::__construct_at(__r++, __compute_chunk(__partitions.__chunk_size_)); + + // handle last chunk + std::__construct_at(__r, __last1, __last2, __result); + + __libdispatch::__dispatch_apply(__partitions.__chunk_count_, [&](size_t __index) { + auto __first_iters = __ranges[__index]; + auto __last_iters = __ranges[__index + 1]; + __leaf_merge( + __first_iters.__mid1_, + __last_iters.__mid1_, + __first_iters.__mid2_, + __last_iters.__mid2_, + __first_iters.__result_, + __comp); }); + + return __empty{}; } template -_LIBCPP_HIDE_FROM_ABI _Value __parallel_transform_reduce( +_LIBCPP_HIDE_FROM_ABI optional<_Value> __parallel_transform_reduce( _RandomAccessIterator __first, _RandomAccessIterator __last, _Transform __transform, @@ -216,26 +236,26 @@ } }); - return std::__terminate_on_exception([&] { - return std::reduce( - std::make_move_iterator(__values.get()), - std::make_move_iterator(__values.get() + __partitions.__chunk_count_), - std::move(__init), - __combiner); - }); + return std::reduce( + std::make_move_iterator(__values.get()), + std::make_move_iterator(__values.get() + __partitions.__chunk_count_), + std::move(__init), + __combiner); } template -_LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort( +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_stable_sort( _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp, _LeafSort __leaf_sort) { const auto __size = __last - __first; auto __partitions = __libdispatch::__partition_chunks(__size); if (__partitions.__chunk_count_ == 0) - return; + return __empty{}; - if (__partitions.__chunk_count_ == 1) - return __leaf_sort(__first, __last, __comp); + if (__partitions.__chunk_count_ == 1) { + __leaf_sort(__first, __last, __comp); + return __empty{}; + } using _Value = __iter_value_type<_RandomAccessIterator>; @@ -247,70 +267,70 @@ // TODO: use __uninitialized_buffer unique_ptr<_Value[], decltype(__destroy)> __values(std::allocator<_Value>().allocate(__size), __destroy); - return std::__terminate_on_exception([&] { - // Initialize all elements to a moved-from state - // TODO: Don't do this - this can be done in the first merge - see https://llvm.org/PR63928 - std::__construct_at(__values.get(), std::move(*__first)); - for (__iter_diff_t<_RandomAccessIterator> __i = 1; __i != __size; ++__i) { - std::__construct_at(__values.get() + __i, std::move(__values.get()[__i - 1])); - } - *__first = std::move(__values.get()[__size - 1]); - - __libdispatch::__dispatch_parallel_for( - __partitions, - __first, - [&__leaf_sort, &__comp](_RandomAccessIterator __chunk_first, _RandomAccessIterator __chunk_last) { - __leaf_sort(std::move(__chunk_first), std::move(__chunk_last), __comp); - }); - - bool __objects_are_in_buffer = false; - do { - const auto __old_chunk_size = __partitions.__chunk_size_; - if (__partitions.__chunk_count_ % 2 == 1) { - auto __inplace_merge_chunks = [&__comp, &__partitions](auto __first_chunk_begin) { - std::inplace_merge( - __first_chunk_begin, - __first_chunk_begin + __partitions.__first_chunk_size_, - __first_chunk_begin + __partitions.__first_chunk_size_ + __partitions.__chunk_size_, - __comp); - }; - if (__objects_are_in_buffer) - __inplace_merge_chunks(__values.get()); - else - __inplace_merge_chunks(__first); - __partitions.__first_chunk_size_ += 2 * __partitions.__chunk_size_; - } else { - __partitions.__first_chunk_size_ += __partitions.__chunk_size_; - } - - __partitions.__chunk_size_ *= 2; - __partitions.__chunk_count_ /= 2; - - auto __merge_chunks = [__partitions, __old_chunk_size, &__comp](auto __from_first, auto __to_first) { - __libdispatch::__dispatch_parallel_for( - __partitions, - __from_first, - [__old_chunk_size, &__from_first, &__to_first, &__comp](auto __chunk_first, auto __chunk_last) { - std::merge(std::make_move_iterator(__chunk_first), - std::make_move_iterator(__chunk_last - __old_chunk_size), - std::make_move_iterator(__chunk_last - __old_chunk_size), - std::make_move_iterator(__chunk_last), - __to_first + (__chunk_first - __from_first), - __comp); - }); + // Initialize all elements to a moved-from state + // TODO: Don't do this - this can be done in the first merge - see https://llvm.org/PR63928 + std::__construct_at(__values.get(), std::move(*__first)); + for (__iter_diff_t<_RandomAccessIterator> __i = 1; __i != __size; ++__i) { + std::__construct_at(__values.get() + __i, std::move(__values.get()[__i - 1])); + } + *__first = std::move(__values.get()[__size - 1]); + + __libdispatch::__dispatch_parallel_for( + __partitions, + __first, + [&__leaf_sort, &__comp](_RandomAccessIterator __chunk_first, _RandomAccessIterator __chunk_last) { + __leaf_sort(std::move(__chunk_first), std::move(__chunk_last), __comp); + }); + + bool __objects_are_in_buffer = false; + do { + const auto __old_chunk_size = __partitions.__chunk_size_; + if (__partitions.__chunk_count_ % 2 == 1) { + auto __inplace_merge_chunks = [&__comp, &__partitions](auto __first_chunk_begin) { + std::inplace_merge( + __first_chunk_begin, + __first_chunk_begin + __partitions.__first_chunk_size_, + __first_chunk_begin + __partitions.__first_chunk_size_ + __partitions.__chunk_size_, + __comp); }; - if (__objects_are_in_buffer) - __merge_chunks(__values.get(), __first); + __inplace_merge_chunks(__values.get()); else - __merge_chunks(__first, __values.get()); - __objects_are_in_buffer = !__objects_are_in_buffer; - } while (__partitions.__chunk_count_ > 1); - - if (__objects_are_in_buffer) { - std::move(__values.get(), __values.get() + __size, __first); + __inplace_merge_chunks(__first); + __partitions.__first_chunk_size_ += 2 * __partitions.__chunk_size_; + } else { + __partitions.__first_chunk_size_ += __partitions.__chunk_size_; } - }); + + __partitions.__chunk_size_ *= 2; + __partitions.__chunk_count_ /= 2; + + auto __merge_chunks = [__partitions, __old_chunk_size, &__comp](auto __from_first, auto __to_first) { + __libdispatch::__dispatch_parallel_for( + __partitions, + __from_first, + [__old_chunk_size, &__from_first, &__to_first, &__comp](auto __chunk_first, auto __chunk_last) { + std::merge(std::make_move_iterator(__chunk_first), + std::make_move_iterator(__chunk_last - __old_chunk_size), + std::make_move_iterator(__chunk_last - __old_chunk_size), + std::make_move_iterator(__chunk_last), + __to_first + (__chunk_first - __from_first), + __comp); + }); + }; + + if (__objects_are_in_buffer) + __merge_chunks(__values.get(), __first); + else + __merge_chunks(__first, __values.get()); + __objects_are_in_buffer = !__objects_are_in_buffer; + } while (__partitions.__chunk_count_ > 1); + + if (__objects_are_in_buffer) { + std::move(__values.get(), __values.get() + __size, __first); + } + + return __empty{}; } _LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {} diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h @@ -15,7 +15,7 @@ #include <__iterator/concepts.h> #include <__type_traits/is_execution_policy.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -23,6 +23,9 @@ #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template -_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_merge( +_LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_merge( __cpu_backend_tag, _ForwardIterator1 __first1, _ForwardIterator1 __last1, @@ -42,31 +45,32 @@ __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value && __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value && __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) { - return std::__terminate_on_exception([&] { - __par_backend::__parallel_merge( - __first1, - __last1, - __first2, - __last2, - __result, - __comp, - [](_ForwardIterator1 __g_first1, - _ForwardIterator1 __g_last1, - _ForwardIterator2 __g_first2, - _ForwardIterator2 __g_last2, - _ForwardOutIterator __g_result, - _Comp __g_comp) { - return std::__pstl_merge<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, - std::move(__g_first1), - std::move(__g_last1), - std::move(__g_first2), - std::move(__g_last2), - std::move(__g_result), - std::move(__g_comp)); - }); - return __result + (__last1 - __first1) + (__last2 - __first2); - }); + auto __res = __par_backend::__parallel_merge( + __first1, + __last1, + __first2, + __last2, + __result, + __comp, + [](_ForwardIterator1 __g_first1, + _ForwardIterator1 __g_last1, + _ForwardIterator2 __g_first2, + _ForwardIterator2 __g_last2, + _ForwardOutIterator __g_result, + _Comp __g_comp) { + [[maybe_unused]] auto __g_res = std::__pstl_merge<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, + std::move(__g_first1), + std::move(__g_last1), + std::move(__g_first2), + std::move(__g_last2), + std::move(__g_result), + std::move(__g_comp)); + _LIBCPP_ASSERT_INTERNAL(__g_res, "unsed/sed should never try to allocate!"); + }); + if (!__res) + return nullopt; + return __result + (__last1 - __first1) + (__last2 - __first2); } else { return std::merge(__first1, __last1, __first2, __last2, __result, __comp); } @@ -74,6 +78,8 @@ _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_MERGE_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h @@ -11,8 +11,10 @@ #define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_SERIAL_H #include <__config> +#include <__utility/empty.h> #include <__utility/move.h> #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -20,26 +22,32 @@ #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD namespace __par_backend { inline namespace __serial_cpu_backend { template -_LIBCPP_HIDE_FROM_ABI void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) { +_LIBCPP_HIDE_FROM_ABI optional<__empty> +__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) { __f(__first, __last); + return __empty{}; } template -_LIBCPP_HIDE_FROM_ABI _Tp +_LIBCPP_HIDE_FROM_ABI optional<_Tp> __parallel_transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) { return __reduce(std::move(__first), std::move(__last), std::move(__init)); } template -_LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort( +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_stable_sort( _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) { __leaf_sort(__first, __last, __comp); + return __empty{}; } _LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {} @@ -49,7 +57,7 @@ class _RandomAccessIterator3, class _Compare, class _LeafMerge> -_LIBCPP_HIDE_FROM_ABI void __parallel_merge( +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_merge( _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2, @@ -58,6 +66,7 @@ _Compare __comp, _LeafMerge __leaf_merge) { __leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp); + return __empty{}; } // TODO: Complete this list @@ -67,6 +76,8 @@ _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && && _LIBCPP_STD_VER >= 17 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_SERIAL_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h @@ -13,7 +13,8 @@ #include <__algorithm/stable_sort.h> #include <__config> #include <__type_traits/is_execution_policy.h> -#include <__utility/terminate_on_exception.h> +#include <__utility/empty.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -24,17 +25,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI optional<__empty> __pstl_stable_sort(__cpu_backend_tag, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) { if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) { - std::__terminate_on_exception([&] { - __par_backend::__parallel_stable_sort( - __first, __last, __comp, [](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) { - std::stable_sort(__g_first, __g_last, __g_comp); - }); - }); + return __par_backend::__parallel_stable_sort( + __first, __last, __comp, [](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) { + std::stable_sort(__g_first, __g_last, __g_comp); + }); } else { std::stable_sort(__first, __last, __comp); + return __empty{}; } } diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h @@ -11,8 +11,10 @@ #include <__assert> #include <__config> +#include <__utility/empty.h> #include <__utility/move.h> #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -32,20 +34,23 @@ inline namespace __thread_cpu_backend { template -_LIBCPP_HIDE_FROM_ABI void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) { +_LIBCPP_HIDE_FROM_ABI optional<__empty> +__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) { __f(__first, __last); + return __empty{}; } template -_LIBCPP_HIDE_FROM_ABI _Tp +_LIBCPP_HIDE_FROM_ABI optional<_Tp> __parallel_transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) { return __reduce(std::move(__first), std::move(__last), std::move(__init)); } template -_LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort( +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_stable_sort( _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) { __leaf_sort(__first, __last, __comp); + return __empty{}; } _LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {} @@ -55,7 +60,7 @@ class _RandomAccessIterator3, class _Compare, class _LeafMerge> -_LIBCPP_HIDE_FROM_ABI void __parallel_merge( +_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_merge( _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1, _RandomAccessIterator2 __first2, @@ -64,6 +69,7 @@ _Compare __comp, _LeafMerge __leaf_merge) { __leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp); + return __empty{}; } } // namespace __thread_cpu_backend diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h @@ -17,7 +17,7 @@ #include <__type_traits/enable_if.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -25,6 +25,9 @@ #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template @@ -37,7 +40,7 @@ } template -_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform( +_LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_transform( __cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, @@ -46,13 +49,13 @@ if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value && __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) { - std::__terminate_on_exception([&] { - std::__par_backend::__parallel_for( - __first, __last, [__op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { - return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, __brick_first, __brick_last, __result + (__brick_first - __first), __op); - }); - }); + std::__par_backend::__parallel_for( + __first, __last, [__op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) { + auto __res = std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, __brick_first, __brick_last, __result + (__brick_first - __first), __op); + _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); + return *std::move(__res); + }); return __result + (__last - __first); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value && @@ -83,7 +86,7 @@ class _ForwardOutIterator, class _BinaryOperation, enable_if_t>, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform( +_LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_transform( __cpu_backend_tag, _ForwardIterator1 __first1, _ForwardIterator1 __last1, @@ -94,20 +97,20 @@ __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value && __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value && __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) { - std::__terminate_on_exception([&] { - std::__par_backend::__parallel_for( - __first1, - __last1, - [__op, __first1, __first2, __result](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) { - return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, - __brick_first, - __brick_last, - __first2 + (__brick_first - __first1), - __result + (__brick_first - __first1), - __op); - }); - }); + auto __res = std::__par_backend::__parallel_for( + __first1, + __last1, + [__op, __first1, __first2, __result](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) { + return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, + __brick_first, + __brick_last, + __first2 + (__brick_first - __first1), + __result + (__brick_first - __first1), + __op); + }); + if (!__res) + return nullopt; return __result + (__last1 - __first1); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value && @@ -128,6 +131,8 @@ _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 #endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_TRANSFORM_H diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h --- a/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h +++ b/libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h @@ -18,8 +18,8 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/operation_traits.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -98,7 +98,7 @@ class _Tp, class _BinaryOperation1, class _BinaryOperation2> -_LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce( +_LIBCPP_HIDE_FROM_ABI optional<_Tp> __pstl_transform_reduce( __cpu_backend_tag, _ForwardIterator1 __first1, _ForwardIterator1 __last1, @@ -109,27 +109,25 @@ if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value && __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) { - return std::__terminate_on_exception([&] { - return __par_backend::__parallel_transform_reduce( - __first1, - std::move(__last1), - [__first1, __first2, __transform](_ForwardIterator1 __iter) { - return __transform(*__iter, *(__first2 + (__iter - __first1))); - }, - std::move(__init), - std::move(__reduce), - [__first1, __first2, __reduce, __transform]( - _ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _Tp __brick_init) { - return std::__pstl_transform_reduce<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, - __brick_first, - std::move(__brick_last), - __first2 + (__brick_first - __first1), - std::move(__brick_init), - std::move(__reduce), - std::move(__transform)); - }); - }); + return __par_backend::__parallel_transform_reduce( + __first1, + std::move(__last1), + [__first1, __first2, __transform](_ForwardIterator1 __iter) { + return __transform(*__iter, *(__first2 + (__iter - __first1))); + }, + std::move(__init), + std::move(__reduce), + [__first1, __first2, __reduce, __transform]( + _ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last, _Tp __brick_init) { + return *std::__pstl_transform_reduce<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, + __brick_first, + std::move(__brick_last), + __first2 + (__brick_first - __first1), + std::move(__brick_init), + std::move(__reduce), + std::move(__transform)); + }); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value && __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) { @@ -149,7 +147,7 @@ } template -_LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce( +_LIBCPP_HIDE_FROM_ABI optional<_Tp> __pstl_transform_reduce( __cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, @@ -158,23 +156,23 @@ _UnaryOperation __transform) { if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { - return std::__terminate_on_exception([&] { - return __par_backend::__parallel_transform_reduce( - std::move(__first), - std::move(__last), - [__transform](_ForwardIterator __iter) { return __transform(*__iter); }, - std::move(__init), - __reduce, - [__transform, __reduce](auto __brick_first, auto __brick_last, _Tp __brick_init) { - return std::__pstl_transform_reduce<__remove_parallel_policy_t<_ExecutionPolicy>>( - __cpu_backend_tag{}, - std::move(__brick_first), - std::move(__brick_last), - std::move(__brick_init), - std::move(__reduce), - std::move(__transform)); - }); - }); + return __par_backend::__parallel_transform_reduce( + std::move(__first), + std::move(__last), + [__transform](_ForwardIterator __iter) { return __transform(*__iter); }, + std::move(__init), + __reduce, + [__transform, __reduce](auto __brick_first, auto __brick_last, _Tp __brick_init) { + auto __res = std::__pstl_transform_reduce<__remove_parallel_policy_t<_ExecutionPolicy>>( + __cpu_backend_tag{}, + std::move(__brick_first), + std::move(__brick_last), + std::move(__brick_init), + std::move(__reduce), + std::move(__transform)); + _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!"); + return *std::move(__res); + }); } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { return std::__simd_transform_reduce( diff --git a/libcxx/include/__algorithm/pstl_copy.h b/libcxx/include/__algorithm/pstl_copy.h --- a/libcxx/include/__algorithm/pstl_copy.h +++ b/libcxx/include/__algorithm/pstl_copy.h @@ -22,6 +22,7 @@ #include <__type_traits/is_trivially_copyable.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -41,18 +42,34 @@ class _ForwardOutIterator, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator -copy(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> +__copy(_ExecutionPolicy&& __policy, + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _ForwardOutIterator&& __result) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_copy), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _ForwardOutIterator __g_result) { - return std::transform(__policy, __g_first, __g_last, __g_result, __identity()); + return std::__transform(__policy, __g_first, __g_last, __g_result, __identity()); }, std::move(__first), std::move(__last), std::move(__result)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator +copy(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result) { + auto __res = std::__copy(__policy, std::move(__first), std::move(__last), std::move(__result)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + template void __pstl_copy_n(); @@ -62,21 +79,36 @@ class _Size, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator -copy_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _ForwardOutIterator __result) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __copy_n( + _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _Size&& __n, _ForwardOutIterator&& __result) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_copy_n), - [&__policy](_ForwardIterator __g_first, _Size __g_n, _ForwardOutIterator __g_result) { + [&__policy]( + _ForwardIterator __g_first, _Size __g_n, _ForwardOutIterator __g_result) -> optional<_ForwardIterator> { if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) - return std::copy(__policy, __g_first, __g_first + __g_n, __g_result); + return std::__copy(__policy, std::move(__g_first), std::move(__g_first + __g_n), std::move(__g_result)); else return std::copy_n(__g_first, __g_n, __g_result); }, std::move(__first), - __n, + std::move(__n), std::move(__result)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator +copy_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _ForwardOutIterator __result) { + auto __res = std::__copy_n(__policy, std::move(__first), std::move(__n), std::move(__result)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_count.h b/libcxx/include/__algorithm/pstl_count.h --- a/libcxx/include/__algorithm/pstl_count.h +++ b/libcxx/include/__algorithm/pstl_count.h @@ -23,7 +23,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -41,13 +41,13 @@ class _Predicate, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI __iter_diff_t<_ForwardIterator> -count_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_diff_t<_ForwardIterator>> __count_if( + _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept { using __diff_t = __iter_diff_t<_ForwardIterator>; return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_count_if), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { - return std::transform_reduce( + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) -> optional<__diff_t> { + return std::__transform_reduce( __policy, std::move(__g_first), std::move(__g_last), @@ -60,6 +60,19 @@ std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI __iter_diff_t<_ForwardIterator> +count_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + auto __res = std::__count_if(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + template void __pstl_count(); // declaration needed for the frontend dispatch below @@ -68,11 +81,12 @@ class _Tp, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI __iter_diff_t<_ForwardIterator> -count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_diff_t<_ForwardIterator>> +__count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_count), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) { + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) + -> optional<__iter_diff_t<_ForwardIterator>> { return std::count_if(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __v) { return __v == __g_value; }); @@ -82,6 +96,19 @@ __value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI __iter_diff_t<_ForwardIterator> +count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + auto __res = std::__count(__policy, std::move(__first), std::move(__last), __value); + if (!__res) + std::__throw_bad_alloc(); + return *__res; +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_fill.h b/libcxx/include/__algorithm/pstl_fill.h --- a/libcxx/include/__algorithm/pstl_fill.h +++ b/libcxx/include/__algorithm/pstl_fill.h @@ -20,7 +20,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -38,13 +38,13 @@ class _Tp, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { +_LIBCPP_HIDE_FROM_ABI optional<__empty> +__fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) noexcept { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); - std::__pstl_frontend_dispatch( + return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill), [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) { - std::for_each(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) { + return std::__for_each(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) { __element = __g_value; }); }, @@ -53,6 +53,18 @@ __value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + if (!std::__fill(__policy, std::move(__first), std::move(__last), __value)) + std::__throw_bad_alloc(); +} + template void __pstl_fill_n(); // declaration needed for the frontend dispatch below @@ -62,22 +74,36 @@ class _Tp, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -fill_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _SizeT __n, const _Tp& __value) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__fill_n(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _SizeT&& __n, const _Tp& __value) noexcept { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); - std::__pstl_frontend_dispatch( + return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill_n), [&](_ForwardIterator __g_first, _SizeT __g_n, const _Tp& __g_value) { if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) std::fill(__policy, __g_first, __g_first + __g_n, __g_value); else std::fill_n(__g_first, __g_n, __g_value); + return optional<__empty>{__empty{}}; }, std::move(__first), - __n, + std::move(__n), __value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +fill_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _SizeT __n, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + if (!std::__fill_n(__policy, std::move(__first), std::move(__n), __value)) + std::__throw_bad_alloc(); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_find.h b/libcxx/include/__algorithm/pstl_find.h --- a/libcxx/include/__algorithm/pstl_find.h +++ b/libcxx/include/__algorithm/pstl_find.h @@ -19,7 +19,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -34,13 +34,26 @@ class _Predicate, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardIterator -find_if(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardIterator>> +__find_if(_ExecutionPolicy&&, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept { using _Backend = typename __select_backend<_RawPolicy>::type; return std::__pstl_find_if<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardIterator +find_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__find_if(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + template void __pstl_find_if_not(); @@ -49,21 +62,36 @@ class _Predicate, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardIterator -find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardIterator>> +__find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find_if_not), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { - return std::find_if(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) { - return !__g_pred(__value); - }); + [&](_ForwardIterator&& __g_first, _ForwardIterator&& __g_last, _Predicate&& __g_pred) + -> optional<__remove_cvref_t<_ForwardIterator>> { + return std::__find_if( + __policy, __g_first, __g_last, [&](__iter_reference<__remove_cvref_t<_ForwardIterator>> __value) { + return !__g_pred(__value); + }); }, std::move(__first), std::move(__last), std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardIterator +find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__find_if_not(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + template void __pstl_find(); @@ -72,21 +100,35 @@ class _Tp, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardIterator -find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardIterator>> +__find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find), - [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) { - return std::find_if(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) { - return __element == __g_value; - }); + [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) -> optional<_ForwardIterator> { + return std::find_if( + __policy, __g_first, __g_last, [&](__iter_reference<__remove_cvref_t<_ForwardIterator>> __element) { + return __element == __g_value; + }); }, std::move(__first), std::move(__last), __value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardIterator +find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__find(__policy, std::move(__first), std::move(__last), __value); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_for_each.h b/libcxx/include/__algorithm/pstl_for_each.h --- a/libcxx/include/__algorithm/pstl_for_each.h +++ b/libcxx/include/__algorithm/pstl_for_each.h @@ -20,8 +20,9 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/void_t.h> +#include <__utility/empty.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -31,16 +32,27 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__for_each(_ExecutionPolicy&&, _ForwardIterator&& __first, _ForwardIterator&& __last, _Function&& __func) noexcept { + using _Backend = typename __select_backend<_RawPolicy>::type; + return std::__pstl_for_each<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__func)); +} + template , enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI void -for_each(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Function __func) { +for_each(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Function __func) { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); - using _Backend = typename __select_backend<_RawPolicy>::type; - std::__pstl_for_each<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__func)); + if (!std::__for_each(__policy, std::move(__first), std::move(__last), std::move(__func))) + std::__throw_bad_alloc(); } template @@ -52,23 +64,38 @@ class _Function, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __size, _Function __func) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _Size&& __size, _Function&& __func) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_for_each_n), - [&](_ForwardIterator __g_first, _Size __g_size, _Function __g_func) { + [&](_ForwardIterator __g_first, _Size __g_size, _Function __g_func) -> optional<__empty> { if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { std::for_each(__policy, std::move(__g_first), __g_first + __g_size, std::move(__g_func)); + return __empty{}; } else { std::for_each_n(std::move(__g_first), __g_size, std::move(__g_func)); + return __empty{}; } }, - __first, - __size, + std::move(__first), + std::move(__size), std::move(__func)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __size, _Function __func) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + auto __res = std::__for_each_n(__policy, std::move(__first), std::move(__size), std::move(__func)); + if (!__res) + std::__throw_bad_alloc(); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_generate.h b/libcxx/include/__algorithm/pstl_generate.h --- a/libcxx/include/__algorithm/pstl_generate.h +++ b/libcxx/include/__algorithm/pstl_generate.h @@ -19,6 +19,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -36,13 +37,13 @@ class _Generator, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -generate(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Generator __gen) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__generate(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Generator&& __gen) { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); - std::__pstl_frontend_dispatch( + return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_generate), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Generator __g_gen) { - std::for_each( + return std::__for_each( __policy, std::move(__g_first), std::move(__g_last), [&](__iter_reference<_ForwardIterator> __element) { __element = __g_gen(); }); @@ -52,6 +53,18 @@ std::move(__gen)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +generate(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Generator __gen) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + if (!std::__generate(__policy, std::move(__first), std::move(__last), std::move(__gen))) + std::__throw_bad_alloc(); +} + template void __pstl_generate_n(); @@ -61,21 +74,34 @@ class _Generator, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -generate_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _Generator __gen) { - _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); - std::__pstl_frontend_dispatch( +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__generate_n(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _Size&& __n, _Generator&& __gen) { + return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_generate_n), [&__policy](_ForwardIterator __g_first, _Size __g_n, _Generator __g_gen) { - std::for_each_n(__policy, std::move(__g_first), __g_n, [&](__iter_reference<_ForwardIterator> __element) { - __element = __g_gen(); - }); + return std::__for_each_n( + __policy, std::move(__g_first), std::move(__g_n), [&](__iter_reference<_ForwardIterator> __element) { + __element = __g_gen(); + }); }, std::move(__first), __n, std::move(__gen)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +generate_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _Generator __gen) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + if (!std::__generate_n(__policy, std::move(__first), std::move(__n), std::move(__gen))) + std::__throw_bad_alloc(); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_is_partitioned.h b/libcxx/include/__algorithm/pstl_is_partitioned.h --- a/libcxx/include/__algorithm/pstl_is_partitioned.h +++ b/libcxx/include/__algorithm/pstl_is_partitioned.h @@ -18,6 +18,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -35,8 +36,8 @@ class _Predicate, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool -is_partitioned(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional __is_partitioned( + _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_is_partitioned), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { @@ -51,6 +52,19 @@ std::move(__pred)); } +template , + enable_if_t, int> = 0> +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool +is_partitioned(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + auto __res = std::__is_partitioned(__policy, std::move(__first), std::move(__last), std::move(__pred)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_merge.h b/libcxx/include/__algorithm/pstl_merge.h --- a/libcxx/include/__algorithm/pstl_merge.h +++ b/libcxx/include/__algorithm/pstl_merge.h @@ -16,6 +16,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -25,6 +26,32 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template , + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> +__merge(_ExecutionPolicy&&, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _ForwardOutIterator __result, + _Comp __comp = {}) noexcept { + using _Backend = typename __select_backend<_RawPolicy>::type; + return std::__pstl_merge<_RawPolicy>( + _Backend{}, + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + std::move(__comp)); +} + template , enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator -merge(_ExecutionPolicy&&, +merge(_ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2, _ForwardOutIterator __result, _Comp __comp = {}) { - using _Backend = typename __select_backend<_RawPolicy>::type; - return std::__pstl_merge<_RawPolicy>( - _Backend{}, + auto __res = std::__merge( + __policy, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__result), std::move(__comp)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/pstl_replace.h b/libcxx/include/__algorithm/pstl_replace.h --- a/libcxx/include/__algorithm/pstl_replace.h +++ b/libcxx/include/__algorithm/pstl_replace.h @@ -18,6 +18,7 @@ #include <__type_traits/enable_if.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -36,19 +37,21 @@ class _Tp, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -replace_if(_ExecutionPolicy&& __policy, - _ForwardIterator __first, - _ForwardIterator __last, - _Pred __pred, - const _Tp& __new_value) { - std::__pstl_frontend_dispatch( +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__replace_if(_ExecutionPolicy&& __policy, + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _Pred&& __pred, + const _Tp& __new_value) noexcept { + return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace_if), - [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred, const _Tp& __g_new_value) { + [&__policy]( + _ForwardIterator&& __g_first, _ForwardIterator&& __g_last, _Pred&& __g_pred, const _Tp& __g_new_value) { std::for_each(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __element) { if (__g_pred(__element)) __element = __g_new_value; }); + return optional<__empty>{__empty{}}; }, std::move(__first), std::move(__last), @@ -56,6 +59,23 @@ __new_value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +replace_if(_ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + _Pred __pred, + const _Tp& __new_value) { + auto __res = std::__replace_if(__policy, std::move(__first), std::move(__last), std::move(__pred), __new_value); + if (!__res) + std::__throw_bad_alloc(); +} + template void __pstl_replace(); @@ -64,17 +84,17 @@ class _Tp, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -replace(_ExecutionPolicy&& __policy, - _ForwardIterator __first, - _ForwardIterator __last, - const _Tp& __old_value, - const _Tp& __new_value) { - std::__pstl_frontend_dispatch( +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> +__replace(_ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + const _Tp& __old_value, + const _Tp& __new_value) noexcept { + return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace), [&__policy]( _ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_old_value, const _Tp& __g_new_value) { - std::replace_if( + return std::__replace_if( __policy, std::move(__g_first), std::move(__g_last), @@ -87,6 +107,21 @@ __new_value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +replace(_ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + const _Tp& __old_value, + const _Tp& __new_value) { + if (!std::__replace(__policy, std::move(__first), std::move(__last), __old_value, __new_value)) + std::__throw_bad_alloc(); +} + template void __pstl_replace_copy_if(); @@ -97,23 +132,26 @@ class _Tp, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void replace_copy_if( +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __replace_copy_if( _ExecutionPolicy&& __policy, - _ForwardIterator __first, - _ForwardIterator __last, - _ForwardOutIterator __result, - _Pred __pred, + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _ForwardOutIterator&& __result, + _Pred&& __pred, const _Tp& __new_value) { - std::__pstl_frontend_dispatch( + return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace_copy_if), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _ForwardOutIterator __g_result, _Pred __g_pred, - const _Tp& __g_new_value) { - std::transform(__policy, __g_first, __g_last, __g_result, [&](__iter_reference<_ForwardIterator> __element) { - return __g_pred(__element) ? __g_new_value : __element; - }); + const _Tp& __g_new_value) -> optional<__empty> { + if (!std::__transform( + __policy, __g_first, __g_last, __g_result, [&](__iter_reference<_ForwardIterator> __element) { + return __g_pred(__element) ? __g_new_value : __element; + })) + return nullopt; + return __empty{}; }, std::move(__first), std::move(__last), @@ -122,30 +160,49 @@ __new_value); } -template -void __pstl_replace_copy(); - template , enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void replace_copy( +_LIBCPP_HIDE_FROM_ABI void replace_copy_if( _ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result, - const _Tp& __old_value, + _Pred __pred, const _Tp& __new_value) { - std::__pstl_frontend_dispatch( + if (!std::__replace_copy_if( + __policy, std::move(__first), std::move(__last), std::move(__result), std::move(__pred), __new_value)) + std::__throw_bad_alloc(); +} + +template +void __pstl_replace_copy(); + +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __replace_copy( + _ExecutionPolicy&& __policy, + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _ForwardOutIterator&& __result, + const _Tp& __old_value, + const _Tp& __new_value) noexcept { + return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_replace_copy), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _ForwardOutIterator __g_result, const _Tp& __g_old_value, const _Tp& __g_new_value) { - return std::replace_copy_if( + return std::__replace_copy_if( __policy, std::move(__g_first), std::move(__g_last), @@ -160,6 +217,24 @@ __new_value); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void replace_copy( + _ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + _ForwardOutIterator __result, + const _Tp& __old_value, + const _Tp& __new_value) { + if (!std::__replace_copy( + __policy, std::move(__first), std::move(__last), std::move(__result), __old_value, __new_value)) + std::__throw_bad_alloc(); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__algorithm/pstl_sort.h b/libcxx/include/__algorithm/pstl_sort.h --- a/libcxx/include/__algorithm/pstl_sort.h +++ b/libcxx/include/__algorithm/pstl_sort.h @@ -16,8 +16,10 @@ #include <__functional/operations.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> +#include <__utility/empty.h> #include <__utility/forward.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -35,18 +37,30 @@ class _Comp, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -sort(_ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) { - std::__pstl_frontend_dispatch( +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __sort( + _ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) noexcept { + return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_sort), [&__policy](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) { std::stable_sort(__policy, std::move(__g_first), std::move(__g_last), std::move(__g_comp)); + return optional<__empty>{__empty{}}; }, std::move(__first), std::move(__last), std::move(__comp)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +sort(_ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) { + if (!std::__sort(__policy, std::move(__first), std::move(__last), std::move(__comp))) + std::__throw_bad_alloc(); +} + template , diff --git a/libcxx/include/__algorithm/pstl_stable_sort.h b/libcxx/include/__algorithm/pstl_stable_sort.h --- a/libcxx/include/__algorithm/pstl_stable_sort.h +++ b/libcxx/include/__algorithm/pstl_stable_sort.h @@ -15,7 +15,9 @@ #include <__type_traits/enable_if.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> +#include <__utility/empty.h> #include <__utility/move.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -30,10 +32,21 @@ class _Comp = less<>, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI void -stable_sort(_ExecutionPolicy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp = {}) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> __stable_sort( + _ExecutionPolicy&&, _RandomAccessIterator&& __first, _RandomAccessIterator&& __last, _Comp&& __comp = {}) noexcept { using _Backend = typename __select_backend<_RawPolicy>::type; - std::__pstl_stable_sort<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__comp)); + return std::__pstl_stable_sort<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__comp)); +} + +template , + class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void stable_sort( + _ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp = {}) { + if (!std::__stable_sort(__policy, std::move(__first), std::move(__last), std::move(__comp))) + std::__throw_bad_alloc(); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/pstl_transform.h b/libcxx/include/__algorithm/pstl_transform.h --- a/libcxx/include/__algorithm/pstl_transform.h +++ b/libcxx/include/__algorithm/pstl_transform.h @@ -16,7 +16,7 @@ #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -26,6 +26,23 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardOutIterator>> +__transform(_ExecutionPolicy&&, + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _ForwardOutIterator&& __result, + _UnaryOperation&& __op) noexcept { + using _Backend = typename __select_backend<_RawPolicy>::type; + return std::__pstl_transform<_RawPolicy>( + _Backend{}, std::move(__first), std::move(__last), std::move(__result), std::move(__op)); +} + template , enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform( - _ExecutionPolicy&&, + _ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result, @@ -41,9 +58,29 @@ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator); _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, decltype(__op(*__first))); + auto __res = std::__transform(__policy, std::move(__first), std::move(__last), std::move(__result), std::move(__op)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_ForwardOutIterator>> +__transform(_ExecutionPolicy&&, + _ForwardIterator1&& __first1, + _ForwardIterator1&& __last1, + _ForwardIterator2&& __first2, + _ForwardOutIterator&& __result, + _BinaryOperation&& __op) noexcept { using _Backend = typename __select_backend<_RawPolicy>::type; return std::__pstl_transform<_RawPolicy>( - _Backend{}, std::move(__first), std::move(__last), std::move(__result), std::move(__op)); + _Backend{}, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__result), std::move(__op)); } template , enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform( - _ExecutionPolicy&&, + _ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, @@ -64,9 +101,11 @@ _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2); _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator); _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, decltype(__op(*__first1, *__first2))); - using _Backend = typename __select_backend<_RawPolicy>::type; - return std::__pstl_transform<_RawPolicy>( - _Backend{}, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__result), std::move(__op)); + auto __res = std::__transform( + __policy, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__result), std::move(__op)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__numeric/pstl_reduce.h b/libcxx/include/__numeric/pstl_reduce.h --- a/libcxx/include/__numeric/pstl_reduce.h +++ b/libcxx/include/__numeric/pstl_reduce.h @@ -33,16 +33,16 @@ class _BinaryOperation = plus<>, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _Tp -reduce(_ExecutionPolicy&& __policy, - _ForwardIterator __first, - _ForwardIterator __last, - _Tp __init, - _BinaryOperation __op = {}) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_Tp> +__reduce(_ExecutionPolicy&& __policy, + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _Tp&& __init, + _BinaryOperation&& __op = {}) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_reduce), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Tp __g_init, _BinaryOperation __g_op) { - return std::transform_reduce( + return std::__transform_reduce( __policy, std::move(__g_first), std::move(__g_last), std::move(__g_init), std::move(__g_op), __identity{}); }, std::move(__first), @@ -53,19 +53,50 @@ template , class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI __iter_value_type<_ForwardIterator> -reduce(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) { +_LIBCPP_HIDE_FROM_ABI _Tp +reduce(_ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + _Tp __init, + _BinaryOperation __op = {}) { + auto __res = std::__reduce(__policy, std::move(__first), std::move(__last), std::move(__init), std::move(__op)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_value_type<_ForwardIterator>> +__reduce(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last) noexcept { return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_reduce), [&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last) { - return std::reduce(__policy, __g_first, __g_last, __iter_value_type<_ForwardIterator>()); + return std::__reduce( + __policy, std::move(__g_first), std::move(__g_last), __iter_value_type<_ForwardIterator>()); }, std::move(__first), std::move(__last)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI __iter_value_type<_ForwardIterator> +reduce(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) { + auto __res = std::__reduce(__policy, std::move(__first), std::move(__last)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__numeric/pstl_transform_reduce.h b/libcxx/include/__numeric/pstl_transform_reduce.h --- a/libcxx/include/__numeric/pstl_transform_reduce.h +++ b/libcxx/include/__numeric/pstl_transform_reduce.h @@ -16,7 +16,7 @@ #include <__numeric/transform_reduce.h> #include <__type_traits/is_execution_policy.h> #include <__utility/move.h> -#include <__utility/terminate_on_exception.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -34,23 +34,53 @@ class _BinaryOperation2, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _Tp transform_reduce( +_LIBCPP_HIDE_FROM_ABI optional<_Tp> __transform_reduce( _ExecutionPolicy&&, + _ForwardIterator1&& __first1, + _ForwardIterator1&& __last1, + _ForwardIterator2&& __first2, + _Tp&& __init, + _BinaryOperation1&& __reduce, + _BinaryOperation2&& __transform) noexcept { + using _Backend = typename __select_backend<_RawPolicy>::type; + return std::__pstl_transform_reduce<_RawPolicy>( + _Backend{}, + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__init), + std::move(__reduce), + std::move(__transform)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp transform_reduce( + _ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _Tp __init, _BinaryOperation1 __reduce, _BinaryOperation2 __transform) { - using _Backend = typename __select_backend<_RawPolicy>::type; - return std::__pstl_transform_reduce<_RawPolicy>( - _Backend{}, + auto __res = std::__transform_reduce( + __policy, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__init), std::move(__reduce), std::move(__transform)); + + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); } // This overload doesn't get a customization point because it's trivial to detect (through e.g. @@ -76,13 +106,13 @@ class _UnaryOperation, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t, int> = 0> -_LIBCPP_HIDE_FROM_ABI _Tp transform_reduce( +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__remove_cvref_t<_Tp>> __transform_reduce( _ExecutionPolicy&&, - _ForwardIterator __first, - _ForwardIterator __last, - _Tp __init, - _BinaryOperation __reduce, - _UnaryOperation __transform) { + _ForwardIterator&& __first, + _ForwardIterator&& __last, + _Tp&& __init, + _BinaryOperation&& __reduce, + _UnaryOperation&& __transform) noexcept { using _Backend = typename __select_backend<_RawPolicy>::type; return std::__pstl_transform_reduce<_RawPolicy>( _Backend{}, @@ -93,6 +123,27 @@ std::move(__transform)); } +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp transform_reduce( + _ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + _Tp __init, + _BinaryOperation __reduce, + _UnaryOperation __transform) { + auto __res = std::__transform_reduce( + __policy, std::move(__first), std::move(__last), std::move(__init), std::move(__reduce), std::move(__transform)); + if (!__res) + std::__throw_bad_alloc(); + return *std::move(__res); +} + _LIBCPP_END_NAMESPACE_STD #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__utility/empty.h b/libcxx/include/__utility/empty.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__utility/empty.h @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___UTILITY_EMPTY_H +#define _LIBCPP___UTILITY_EMPTY_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +struct __empty {}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___UTILITY_EMPTY_H diff --git a/libcxx/include/__utility/terminate_on_exception.h b/libcxx/include/__utility/terminate_on_exception.h deleted file mode 100644 --- a/libcxx/include/__utility/terminate_on_exception.h +++ /dev/null @@ -1,48 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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___UTILITY_TERMINATE_ON_EXCEPTION_H -#define _LIBCPP___UTILITY_TERMINATE_ON_EXCEPTION_H - -#include <__config> -#include <__exception/terminate.h> -#include - -#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -#endif - -#if _LIBCPP_STD_VER >= 17 - -_LIBCPP_BEGIN_NAMESPACE_STD - -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS - -template -_LIBCPP_HIDE_FROM_ABI auto __terminate_on_exception(_Func __func) { - try { - return __func(); - } catch (...) { - std::terminate(); - } -} - -# else // _LIBCPP_HAS_NO_EXCEPTIONS - -template -_LIBCPP_HIDE_FROM_ABI auto __terminate_on_exception(_Func __func) { - return __func(); -} - -# endif // _LIBCPP_HAS_NO_EXCEPTIONS - -_LIBCPP_END_NAMESPACE_STD - -#endif // _LIBCPP_STD_VER >= 17 - -#endif // _LIBCPP___UTILITY_TERMINATE_ON_EXCEPTION_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -2053,6 +2053,7 @@ } module std_private_utility_convert_to_integral [system] { header "__utility/convert_to_integral.h" } module std_private_utility_declval [system] { header "__utility/declval.h" } +module std_private_utility_empty [system] { header "__utility/empty.h" } module std_private_utility_exception_guard [system] { header "__utility/exception_guard.h" } module std_private_utility_exchange [system] { header "__utility/exchange.h" } module std_private_utility_forward [system] { header "__utility/forward.h" } @@ -2088,7 +2089,6 @@ header "__utility/swap.h" export std_private_type_traits_is_swappable } -module std_private_utility_terminate_on_exception [system] { header "__utility/terminate_on_exception.h" } module std_private_utility_to_underlying [system] { header "__utility/to_underlying.h" } module std_private_utility_unreachable [system] { header "__utility/unreachable.h" } diff --git a/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp b/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp --- a/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp +++ b/libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp @@ -17,7 +17,9 @@ #include <__config> #include <__iterator/iterator_traits.h> #include <__iterator/readable_traits.h> +#include <__utility/empty.h> #include +#include struct TestPolicy {}; struct TestBackend {}; @@ -27,7 +29,7 @@ bool pstl_any_of_called = false; template -bool __pstl_any_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { +optional __pstl_any_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { assert(!pstl_any_of_called); pstl_any_of_called = true; return true; @@ -36,7 +38,7 @@ bool pstl_all_of_called = false; template -bool __pstl_all_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { +optional __pstl_all_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { assert(!pstl_all_of_called); pstl_all_of_called = true; return true; @@ -45,25 +47,25 @@ bool pstl_copy_called = false; template -ForwardIterator __pstl_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator) { +optional __pstl_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator res) { assert(!pstl_copy_called); pstl_copy_called = true; - return 0; + return res; } bool pstl_copy_n_called = false; template -ForwardIterator __pstl_copy_n(TestBackend, ForwardIterator, Size, ForwardOutIterator) { +optional __pstl_copy_n(TestBackend, ForwardIterator, Size, ForwardOutIterator res) { assert(!pstl_copy_n_called); pstl_copy_n_called = true; - return 0; + return res; } bool pstl_count_called = false; template -typename std::iterator_traits::difference_type +optional::difference_type> __pstl_count(TestBackend, ForwardIterator, ForwardIterator, const T&) { assert(!pstl_count_called); pstl_count_called = true; @@ -73,7 +75,7 @@ bool pstl_count_if_called = false; template -typename std::iterator_traits::difference_type +optional::difference_type> __pstl_count_if(TestBackend, ForwardIterator, ForwardIterator, Pred) { assert(!pstl_count_if_called); pstl_count_if_called = true; @@ -83,23 +85,25 @@ bool pstl_generate_called = false; template -void __pstl_generate(TestBackend, ForwardIterator, ForwardIterator, Gen) { +optional<__empty> __pstl_generate(TestBackend, ForwardIterator, ForwardIterator, Gen) { assert(!pstl_generate_called); pstl_generate_called = true; + return __empty{}; } bool pstl_generate_n_called = false; template -void __pstl_generate_n(TestBackend, Size, ForwardIterator, Gen) { +optional<__empty> __pstl_generate_n(TestBackend, Size, ForwardIterator, Gen) { assert(!pstl_generate_n_called); pstl_generate_n_called = true; + return __empty{}; } bool pstl_none_of_called = false; template -bool __pstl_none_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { +optional __pstl_none_of(TestBackend, ForwardIterator, ForwardIterator, Pred) { assert(!pstl_none_of_called); pstl_none_of_called = true; return true; @@ -108,164 +112,177 @@ bool pstl_find_called = false; template -ForwardIterator __pstl_find(TestBackend, ForwardIterator, ForwardIterator, Pred) { +optional __pstl_find(TestBackend, ForwardIterator first, ForwardIterator, Pred) { assert(!pstl_find_called); pstl_find_called = true; - return {}; + return first; } bool pstl_find_if_called = false; template -ForwardIterator __pstl_find_if(TestBackend, ForwardIterator, ForwardIterator, Pred) { +optional __pstl_find_if(TestBackend, ForwardIterator first, ForwardIterator, Pred) { assert(!pstl_find_if_called); pstl_find_if_called = true; - return {}; + return first; } bool pstl_find_if_not_called = false; template -ForwardIterator __pstl_find_if_not(TestBackend, ForwardIterator, ForwardIterator, Pred) { +optional __pstl_find_if_not(TestBackend, ForwardIterator first, ForwardIterator, Pred) { assert(!pstl_find_if_not_called); pstl_find_if_not_called = true; - return {}; + return first; } bool pstl_for_each_called = false; template -void __pstl_for_each(TestBackend, ForwardIterator, Size, Func) { +optional<__empty> __pstl_for_each(TestBackend, ForwardIterator, Size, Func) { assert(!pstl_for_each_called); pstl_for_each_called = true; + return __empty{}; } bool pstl_for_each_n_called = false; template -void __pstl_for_each_n(TestBackend, ForwardIterator, Size, Func) { +optional<__empty> __pstl_for_each_n(TestBackend, ForwardIterator, Size, Func) { assert(!pstl_for_each_n_called); pstl_for_each_n_called = true; + return __empty{}; } bool pstl_fill_called = false; template -void __pstl_fill(TestBackend, ForwardIterator, Size, Func) { +optional<__empty> __pstl_fill(TestBackend, ForwardIterator, Size, Func) { assert(!pstl_fill_called); pstl_fill_called = true; + return __empty{}; } bool pstl_fill_n_called = false; template -void __pstl_fill_n(TestBackend, ForwardIterator, Size, Func) { +optional<__empty> __pstl_fill_n(TestBackend, ForwardIterator, Size, Func) { assert(!pstl_fill_n_called); pstl_fill_n_called = true; + return __empty{}; } bool pstl_is_partitioned_called = false; template -bool __pstl_is_partitioned(TestBackend, ForwardIterator, ForwardIterator, Func) { +optional __pstl_is_partitioned(TestBackend, ForwardIterator, ForwardIterator, Func) { assert(!pstl_is_partitioned_called); pstl_is_partitioned_called = true; - return {}; + return true; } bool pstl_replace_called = false; template -void __pstl_replace(TestBackend, ForwardIterator, ForwardIterator, const T&, const T&) { +optional<__empty> __pstl_replace(TestBackend, ForwardIterator, ForwardIterator, const T&, const T&) { assert(!pstl_replace_called); pstl_replace_called = true; + return __empty{}; } bool pstl_replace_if_called = false; template -void __pstl_replace_if(TestBackend, ForwardIterator, ForwardIterator, Func, const T&) { +optional<__empty> __pstl_replace_if(TestBackend, ForwardIterator, ForwardIterator, Func, const T&) { assert(!pstl_replace_if_called); pstl_replace_if_called = true; + return __empty{}; } bool pstl_replace_copy_called = false; template -void __pstl_replace_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, const T&, const T&) { +optional<__empty> +__pstl_replace_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, const T&, const T&) { assert(!pstl_replace_copy_called); pstl_replace_copy_called = true; + return __empty{}; } bool pstl_replace_copy_if_called = false; template -void __pstl_replace_copy_if(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, Func, const T&) { +optional<__empty> +__pstl_replace_copy_if(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, Func, const T&) { assert(!pstl_replace_copy_if_called); pstl_replace_copy_if_called = true; + return __empty{}; } bool pstl_unary_transform_called = false; template -ForwardOutIterator __pstl_transform(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, UnaryOperation) { +optional +__pstl_transform(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator res, UnaryOperation) { assert(!pstl_unary_transform_called); pstl_unary_transform_called = true; - return {}; + return res; } bool pstl_binary_transform_called = false; template -ForwardOutIterator __pstl_transform( - TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, ForwardOutIterator, BinaryOperation) { +optional __pstl_transform( + TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, ForwardOutIterator res, BinaryOperation) { assert(!pstl_binary_transform_called); pstl_binary_transform_called = true; - return {}; + return res; } bool pstl_reduce_with_init_called = false; template -T __pstl_reduce(TestBackend, ForwardIterator, ForwardIterator, T, BinaryOperation) { +optional __pstl_reduce(TestBackend, ForwardIterator, ForwardIterator, T v, BinaryOperation) { assert(!pstl_reduce_with_init_called); pstl_reduce_with_init_called = true; - return {}; + return v; } bool pstl_reduce_without_init_called = false; template -typename std::iterator_traits::value_type -__pstl_reduce(TestBackend, ForwardIterator, ForwardIterator) { +optional::value_type> +__pstl_reduce(TestBackend, ForwardIterator first, ForwardIterator) { assert(!pstl_reduce_without_init_called); pstl_reduce_without_init_called = true; - return {}; + return *first; } bool pstl_sort_called = false; template -void __pstl_sort(TestBackend, RandomAccessIterator, RandomAccessIterator, Comp) { +optional<__empty> __pstl_sort(TestBackend, RandomAccessIterator, RandomAccessIterator, Comp) { assert(!pstl_sort_called); pstl_sort_called = true; + return __empty{}; } bool pstl_stable_sort_called = false; template -void __pstl_stable_sort(TestBackend, RandomAccessIterator, RandomAccessIterator, Comp) { +optional<__empty> __pstl_stable_sort(TestBackend, RandomAccessIterator, RandomAccessIterator, Comp) { assert(!pstl_stable_sort_called); pstl_stable_sort_called = true; + return __empty{}; } bool pstl_unary_transform_reduce_called = false; template -T __pstl_transform_reduce(TestBackend, ForwardIterator, ForwardIterator, T, UnaryOperation, BinaryOperation) { +T __pstl_transform_reduce(TestBackend, ForwardIterator, ForwardIterator, T v, UnaryOperation, BinaryOperation) { assert(!pstl_unary_transform_reduce_called); pstl_unary_transform_reduce_called = true; - return {}; + return v; } bool pstl_binary_transform_reduce_called = false; @@ -277,10 +294,10 @@ class BinaryOperation1, class BinaryOperation2> typename std::iterator_traits::value_type __pstl_transform_reduce( - TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, T, BinaryOperation1, BinaryOperation2) { + TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, T v, BinaryOperation1, BinaryOperation2) { assert(!pstl_binary_transform_reduce_called); pstl_binary_transform_reduce_called = true; - return {}; + return v; } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -6,7 +6,6 @@ algorithm cstdint algorithm cstdlib algorithm cstring -algorithm ctime algorithm cwchar algorithm execution algorithm initializer_list @@ -15,7 +14,7 @@ algorithm limits algorithm memory algorithm new -algorithm ratio +algorithm optional algorithm stdexcept algorithm type_traits algorithm utility @@ -584,15 +583,12 @@ numeric concepts numeric cstddef numeric cstdint -numeric cstring -numeric ctime numeric execution numeric functional -numeric initializer_list numeric iterator numeric limits numeric new -numeric ratio +numeric optional numeric type_traits numeric version optional atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -6,7 +6,6 @@ algorithm cstdint algorithm cstdlib algorithm cstring -algorithm ctime algorithm cwchar algorithm execution algorithm initializer_list @@ -15,7 +14,7 @@ algorithm limits algorithm memory algorithm new -algorithm ratio +algorithm optional algorithm stdexcept algorithm type_traits algorithm utility @@ -589,15 +588,12 @@ numeric concepts numeric cstddef numeric cstdint -numeric cstring -numeric ctime numeric execution numeric functional -numeric initializer_list numeric iterator numeric limits numeric new -numeric ratio +numeric optional numeric type_traits numeric version optional atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -6,7 +6,6 @@ algorithm cstdint algorithm cstdlib algorithm cstring -algorithm ctime algorithm cwchar algorithm execution algorithm initializer_list @@ -15,7 +14,7 @@ algorithm limits algorithm memory algorithm new -algorithm ratio +algorithm optional algorithm stdexcept algorithm type_traits algorithm utility @@ -591,15 +590,12 @@ numeric concepts numeric cstddef numeric cstdint -numeric cstring -numeric ctime numeric execution numeric functional -numeric initializer_list numeric iterator numeric limits numeric new -numeric ratio +numeric optional numeric type_traits numeric version optional atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -6,7 +6,6 @@ algorithm cstdint algorithm cstdlib algorithm cstring -algorithm ctime algorithm cwchar algorithm execution algorithm initializer_list @@ -15,7 +14,7 @@ algorithm limits algorithm memory algorithm new -algorithm ratio +algorithm optional algorithm stdexcept algorithm type_traits algorithm utility @@ -591,15 +590,12 @@ numeric concepts numeric cstddef numeric cstdint -numeric cstring -numeric ctime numeric execution numeric functional -numeric initializer_list numeric iterator numeric limits numeric new -numeric ratio +numeric optional numeric type_traits numeric version optional atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -6,7 +6,6 @@ algorithm cstdint algorithm cstdlib algorithm cstring -algorithm ctime algorithm cwchar algorithm execution algorithm initializer_list @@ -15,7 +14,7 @@ algorithm limits algorithm memory algorithm new -algorithm ratio +algorithm optional algorithm stdexcept algorithm type_traits algorithm utility @@ -596,15 +595,12 @@ numeric concepts numeric cstddef numeric cstdint -numeric cstring -numeric ctime numeric execution numeric functional -numeric initializer_list numeric iterator numeric limits numeric new -numeric ratio +numeric optional numeric type_traits numeric version optional atomic diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -9,6 +9,7 @@ algorithm iosfwd algorithm limits algorithm new +algorithm optional algorithm ratio algorithm version any cstddef @@ -429,6 +430,7 @@ numeric initializer_list numeric limits numeric new +numeric optional numeric ratio numeric version optional compare diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv --- a/libcxx/test/libcxx/transitive_includes/cxx26.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -9,6 +9,7 @@ algorithm iosfwd algorithm limits algorithm new +algorithm optional algorithm ratio algorithm version any cstddef @@ -429,6 +430,7 @@ numeric initializer_list numeric limits numeric new +numeric optional numeric ratio numeric version optional compare diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::fill(ExecutionPolicy) and std::fill_n(ExecutionPolicy) terminate on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +#ifndef TEST_HAS_NO_EXCEPTIONS +struct ThrowOnCopy { + ThrowOnCopy& operator=(const ThrowOnCopy&) { throw int{}; } +}; +#endif + +int main(int, char**) { + ThrowOnCopy a[2]{}; + int b[2]{}; + + test_execution_policies([&](auto&& policy) { + // std::fill + EXPECT_STD_TERMINATE([&] { (void)std::fill(policy, std::begin(a), std::end(a), ThrowOnCopy{}); }); + EXPECT_STD_TERMINATE([&] { + try { + (void)std::fill( + policy, util::throw_on_move_iterator(std::begin(b), 1), util::throw_on_move_iterator(std::end(b), 1), 0); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::fill_n + EXPECT_STD_TERMINATE([&] { (void)std::fill_n(policy, std::begin(a), std::size(a), ThrowOnCopy{}); }); + EXPECT_STD_TERMINATE([&] { + try { + (void)std::fill_n(policy, util::throw_on_move_iterator(std::begin(b), 1), std::size(b), 0); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp @@ -61,24 +61,8 @@ } }; -#ifndef TEST_HAS_NO_EXCEPTIONS -struct ThrowOnCopy { - ThrowOnCopy& operator=(const ThrowOnCopy&) { throw int{}; } -}; -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCopy a[2]; - try { - (void)std::fill(std::execution::par, std::begin(a), std::end(a), ThrowOnCopy{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp @@ -61,24 +61,8 @@ } }; -#ifndef TEST_HAS_NO_EXCEPTIONS -struct ThrowOnCopy { - ThrowOnCopy& operator=(const ThrowOnCopy&) { throw int{}; } -}; -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCopy a[2]; - try { - (void)std::fill_n(std::execution::par, std::begin(a), std::size(a), ThrowOnCopy{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp @@ -0,0 +1,117 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::replace(ExecutionPolicy), std::replace_if(ExecutionPolicy), std::replace_copy(ExecutionPolicy) +// and std::replace_copy_if(ExecutionPolicy) terminate on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +struct ThrowOnCompare {}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } +#endif + +int main(int, char**) { + test_execution_policies([&](auto&& policy) { + // std::replace + EXPECT_STD_TERMINATE([&] { + ThrowOnCompare a[2]{}; + (void)std::replace(policy, std::begin(a), std::end(a), ThrowOnCompare{}, ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::replace( + policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1), 1, 2); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::replace_if + EXPECT_STD_TERMINATE([&] { + ThrowOnCompare a[2]{}; + (void)std::replace_if( + policy, std::begin(a), std::end(a), [](ThrowOnCompare&) -> bool { throw int{}; }, ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::replace_if( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) { return true; }, + 2); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::replace_copy + EXPECT_STD_TERMINATE([&] { + ThrowOnCompare a[2]{}; + (void)std::replace_copy(policy, std::begin(a), std::end(a), std::begin(a), ThrowOnCompare{}, ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::replace_copy( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + 1, + 2); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::replace_copy_if + EXPECT_STD_TERMINATE([&] { + ThrowOnCompare a[2]{}; + (void)std::replace_copy_if( + policy, + std::begin(a), + std::end(a), + std::begin(a), + [](ThrowOnCompare& i) { return i == i; }, + ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::replace_copy_if( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + [](int) { return true; }, + 2); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp @@ -73,24 +73,8 @@ } }; -struct ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCompare a[2]; - try { - (void)std::replace(std::execution::par, std::begin(a), std::end(a), ThrowOnCompare{}, ThrowOnCompare{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp @@ -82,25 +82,8 @@ } }; -struct ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCompare a[2]; - try { - (void)std::replace_copy( - std::execution::par, std::begin(a), std::end(a), std::begin(a), ThrowOnCompare{}, ThrowOnCompare{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp @@ -95,30 +95,8 @@ } }; -struct ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCompare a[2]; - try { - (void)std::replace_copy_if( - std::execution::par, - std::begin(a), - std::end(a), - std::begin(a), - [](ThrowOnCompare& i) { return i == i; }, - ThrowOnCompare{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp @@ -78,25 +78,8 @@ } }; -struct ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCompare a[2]; - try { - (void)std::replace_if( - std::execution::par, std::begin(a), std::end(a), [](ThrowOnCompare&) { return false; }, ThrowOnCompare{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.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 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::transform(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([&](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + int a[2]{}; + int b[2]{}; + int c[2]{}; + (void)std::transform( + policy, std::begin(a), std::end(a), std::begin(b), std::begin(c), [](auto v, auto) -> decltype(v) { + throw int{}; + }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::transform( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + [](int i) { return i; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + EXPECT_STD_TERMINATE([&] { + int a[2]{}; + int b[2]{}; + (void)std::transform(policy, std::begin(a), std::end(a), std::begin(b), [](auto v) -> decltype(v) { + throw int{}; + }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::transform( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + std::plus{}); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp @@ -69,15 +69,5 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - (void)std::all_of(std::execution::par, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: no-exceptions + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::all_of(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + (void)std::all_of(policy, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::all_of( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) { return true; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp @@ -63,15 +63,5 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - (void)std::any_of(std::execution::par, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::any_of(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + (void)std::any_of(policy, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::any_of( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) { return true; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.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 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::find(ExecutionPolicy), std::find_if(ExecutionPolicy) and std::find_if_not(ExecutionPolicy) terminate +// on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +struct ThrowOnCompare {}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } +#endif + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + // std::find + EXPECT_STD_TERMINATE([&] { + ThrowOnCompare a[2] = {}; + (void)std::find(policy, std::begin(a), std::end(a), ThrowOnCompare{}); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::find( + policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1), 0); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::find_if + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + (void)std::find_if(policy, std::begin(a), std::end(a), [](int) -> bool { throw int{}; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::find_if( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) { return true; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::find_if_not + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + (void)std::find_if_not(policy, std::begin(a), std::end(a), [](int) -> bool { throw int{}; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::find_if_not( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) { return true; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp @@ -61,24 +61,8 @@ } }; -struct ThrowOnCompare {}; - -#ifndef TEST_HAS_NO_EXCEPTIONS -bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; } -#endif - int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - ThrowOnCompare a[2]; - try { - (void)std::find(std::execution::par, std::begin(a), std::end(a), ThrowOnCompare{}); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp @@ -70,15 +70,5 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - (void)std::find_if(std::execution::par, std::begin(a), std::end(a), [](int) -> bool { throw int{}; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp @@ -71,15 +71,5 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - (void)std::find_if_not(std::execution::par, std::begin(a), std::end(a), [](int) -> bool { throw int{}; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::for_each(ExecutionPolicy) and std::for_each_n(ExecutionPolicy) terminate on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + int a[] = {1, 2}; + // std::for_each + EXPECT_STD_TERMINATE([&] { std::for_each(policy, std::begin(a), std::end(a), [](int) { throw int{}; }); }); + EXPECT_STD_TERMINATE([&] { + try { + (void)std::for_each( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) {}); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + // std::for_each_n + EXPECT_STD_TERMINATE([&] { std::for_each_n(policy, std::data(a), std::size(a), [](int) { throw int{}; }); }); + EXPECT_STD_TERMINATE([&] { + try { + (void)std::for_each_n(policy, util::throw_on_move_iterator(std::begin(a), 1), std::size(a), [](int) {}); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp @@ -51,15 +51,5 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - std::for_each(std::execution::par, std::begin(a), std::end(a), [](int) { throw int{}; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp @@ -50,15 +50,5 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - std::for_each_n(std::execution::par, std::data(a), std::size(a), [](int) { throw int{}; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::none_of(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + (void)std::none_of(policy, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::none_of( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + [](int) { return true; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp @@ -63,15 +63,5 @@ int main(int, char**) { types::for_each(types::forward_iterator_list{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - (void)std::none_of(std::execution::par, std::begin(a), std::end(a), [](int i) -> bool { throw i; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::merge(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + std::merge(policy, std::begin(a), std::end(a), std::begin(a), std::end(a), std::begin(a), [](int, int) -> bool { + throw int{}; + }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::merge( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + std::less{}); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); + + return 0; +} diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::stable_sort(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + int a[] = {1, 2}; + std::stable_sort(policy, std::begin(a), std::end(a), [](int, int) -> bool { throw int{}; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::stable_sort( + policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1)); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp @@ -146,15 +146,5 @@ types::random_access_iterator_list>{}, TestIteratorWithPolicies{}); -#ifndef TEST_HAS_NO_EXCEPTIONS - std::set_terminate(terminate_successful); - int a[] = {1, 2}; - try { - std::stable_sort(std::execution::par, std::begin(a), std::end(a), [](int, int) -> bool { throw int{}; }); - } catch (int) { - assert(false); - } -#endif - return 0; } diff --git a/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::reduce(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([&](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::reduce( + policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1)); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + EXPECT_STD_TERMINATE([&] { + int a[2]{}; + (void)std::reduce(policy, std::begin(a), std::end(a), 1, [](int, int) -> int { throw 1; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::reduce( + policy, util::throw_on_move_iterator(std::begin(a), 1), util::throw_on_move_iterator(std::end(a), 1), 1); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.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 +// UNSUPPORTED: no-exceptions +// REQUIRES: has-unix-headers + +// UNSUPPORTED: libcpp-has-no-incomplete-pstl + +// check that std::reduce(ExecutionPolicy) terminates on user-thrown exceptions + +#include + +#include "check_assertion.h" +#include "test_execution_policies.h" +#include "test_iterators.h" + +int main(int, char**) { + test_execution_policies([&](auto&& policy) { + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::transform_reduce( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + util::throw_on_move_iterator(std::begin(a), 1), + 1); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + + EXPECT_STD_TERMINATE([&] { + int a[2]{}; + (void)std::transform_reduce( + policy, std::begin(a), std::end(a), 1, [](int, int) -> int { throw 1; }, [](int) -> int { return 0; }); + }); + EXPECT_STD_TERMINATE([&] { + try { + int a[] = {1, 2}; + (void)std::transform_reduce( + policy, + util::throw_on_move_iterator(std::begin(a), 1), + util::throw_on_move_iterator(std::end(a), 1), + 1, + std::plus{}, + [](int) -> int { return 0; }); + } catch (const util::iterator_error&) { + assert(false); + } + std::terminate(); // make the test pass in case the algorithm didn't move the iterator + }); + }); +} diff --git a/libcxx/test/support/check_assertion.h b/libcxx/test/support/check_assertion.h --- a/libcxx/test/support/check_assertion.h +++ b/libcxx/test/support/check_assertion.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -24,10 +25,6 @@ #include "test_macros.h" #include "test_allocator.h" -#ifndef _LIBCPP_VERSION -# error "This header may only be used for libc++ tests" -#endif - #if TEST_STD_VER < 11 # error "C++11 or greater is required to use this header" #endif @@ -111,7 +108,7 @@ struct DeathTest { enum ResultKind { - RK_DidNotDie, RK_MatchFound, RK_MatchFailure, RK_SetupFailure, RK_Unknown + RK_DidNotDie, RK_MatchFound, RK_MatchFailure, RK_Terminate, RK_SetupFailure, RK_Unknown }; static const char* ResultKindToString(ResultKind RK) { @@ -122,6 +119,7 @@ CASE(RK_SetupFailure); CASE(RK_MatchFound); CASE(RK_Unknown); + CASE(RK_Terminate); } return "not a result kind"; } @@ -236,6 +234,7 @@ std::string stderr_from_child_; }; +#ifdef _LIBCPP_VERSION void std::__libcpp_verbose_abort(char const* format, ...) { // Extract information from the error message. This has to stay synchronized with // how we format assertions in the library. @@ -252,9 +251,15 @@ } std::exit(DeathTest::RK_MatchFailure); } +#endif // _LIBCPP_VERSION + +[[noreturn]] inline void terminate_handler() { + std::exit(DeathTest::RK_Terminate); +} template inline bool ExpectDeath(const char* stmt, Func&& func, AssertionInfoMatcher Matcher) { + std::set_terminate(terminate_handler); DeathTest DT(Matcher); DeathTest::ResultKind RK = DT.Run(func); auto OnFailure = [&](const char* msg) { @@ -272,6 +277,7 @@ }; switch (RK) { case DeathTest::RK_MatchFound: + case DeathTest::RK_Terminate: return true; case DeathTest::RK_SetupFailure: return OnFailure("child failed to setup test environment"); @@ -293,6 +299,8 @@ /// Assert that the specified expression throws a libc++ debug exception. #define EXPECT_DEATH(...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; } ))) +#define EXPECT_STD_TERMINATE(...) assert(ExpectDeath(#__VA_ARGS__, __VA_ARGS__)) + #define EXPECT_DEATH_MATCHES(Matcher, ...) assert((ExpectDeath(#__VA_ARGS__, [&]() { __VA_ARGS__; }, Matcher))) #define TEST_LIBCPP_ASSERT_FAILURE(expr, message) assert((ExpectDeath(#expr, [&]() { (void)(expr); }, AssertionInfoMatcher(message)))) diff --git a/libcxx/test/support/test_execution_policies.h b/libcxx/test/support/test_execution_policies.h --- a/libcxx/test/support/test_execution_policies.h +++ b/libcxx/test/support/test_execution_policies.h @@ -58,8 +58,4 @@ } }; -#ifndef TEST_HAS_NO_EXCEPTIONS -[[noreturn]] inline void terminate_successful() { std::exit(0); } -#endif - #endif // TEST_SUPPORT_TEST_EXECUTION_POLICIES diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -1420,6 +1420,124 @@ #endif // TEST_STD_VER > 17 +#if TEST_STD_VER >= 17 + +namespace util { +template +class iterator_wrapper { + Iter iter_; + + using iter_traits = std::iterator_traits; + +public: + using iterator_cateory = typename iter_traits::iterator_category; + using value_type = typename iter_traits::value_type; + using difference_type = typename iter_traits::difference_type; + using pointer = typename iter_traits::pointer; + using reference = typename iter_traits::reference; + + constexpr iterator_wrapper() : iter_() {} + constexpr explicit iterator_wrapper(Iter iter) : iter_(iter) {} + + decltype(*iter_) operator*() { return *iter_; } + decltype(*iter_) operator*() const { return *iter_; } + + decltype(iter_[0]) operator[](difference_type v) const { + return iter_[v]; + } + + Derived& operator++() { + ++iter_; + return static_cast(*this); + } + + Derived operator++(int) { + auto tmp = static_cast(*this); + ++(*this); + return tmp; + } + + Derived& operator--() { + --iter_; + return static_cast(*this); + } + + Derived operator--(int) { + auto tmp = static_cast(*this); + --(*this); + return tmp; + } + + iterator_wrapper& operator+=(difference_type i) { + iter_ += i; + return *this; + } + + friend decltype(iter_ - iter_) operator-(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { + return lhs.iter_ - rhs.iter_; + } + + friend Derived operator-(const iterator_wrapper& lhs, difference_type rhs) { + return lhs.iter_ - rhs; + } + + friend Derived operator+(Derived iter, difference_type i) { + iter.iter_ += i; + return iter; + } + + friend bool operator==(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ == rhs.iter_; } + friend bool operator!=(const iterator_wrapper& lhs, const iterator_wrapper& rhs) { return lhs.iter_ != rhs.iter_; } +}; + +class iterator_error : std::runtime_error { +public: + iterator_error(const char* what) : std::runtime_error(what) {} +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +template +class throw_on_move_iterator : public iterator_wrapper, Iter> { + using base = iterator_wrapper, Iter>; + + int moves_until_throw_ = 0; + +public: + using difference_type = typename base::difference_type; + using value_type = typename base::value_type; + using iterator_category = typename base::iterator_cateory; + + throw_on_move_iterator() = default; + throw_on_move_iterator(Iter iter, int moves_until_throw) + : base(std::move(iter)), moves_until_throw_(moves_until_throw) {} + + throw_on_move_iterator(const throw_on_move_iterator& other) : base(other) {} + throw_on_move_iterator& operator=(const throw_on_move_iterator& other) { + static_cast(*this) = other; + return *this; + } + + throw_on_move_iterator(throw_on_move_iterator&& other) + : base(std::move(other)), moves_until_throw_(other.moves_until_throw_ - 1) { + if (moves_until_throw_ == -1) + throw iterator_error("throw_on_move_iterator"); + } + + throw_on_move_iterator& operator=(throw_on_move_iterator&& other) { + moves_until_throw_ = other.moves_until_throw_ - 1; + if (moves_until_throw_ == -1) + throw iterator_error("throw_on_move_iterator"); + return *this; + } +}; + +template +throw_on_move_iterator(Iter) -> throw_on_move_iterator; +#endif // TEST_HAS_NO_EXCEPTIONS +} // namespace util + +#endif // TEST_STD_VER >= 17 + namespace types { template using random_access_iterator_list = diff --git a/libcxx/utils/ci/buildkite-pipeline.yml b/libcxx/utils/ci/buildkite-pipeline.yml --- a/libcxx/utils/ci/buildkite-pipeline.yml +++ b/libcxx/utils/ci/buildkite-pipeline.yml @@ -33,841 +33,6 @@ # # Light pre-commit tests for things like forgetting to update generated files. # - - label: "Generated output" - command: "libcxx/utils/ci/run-buildbot check-generated-output" - artifact_paths: - - "**/generated_output.patch" - - "**/generated_output.status" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - CLANG_FORMAT: "/usr/bin/clang-format-${LLVM_STABLE_VERSION}" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Documentation" - command: "libcxx/utils/ci/run-buildbot documentation" - artifact_paths: - - "**/test-results.xml" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # - # General testing with the default configuration, under all the supported - # Standard modes, with Clang and GCC. This catches most issues upfront. - # The goal of this step is to catch most issues while being very fast. - # - - wait - - - label: "GCC ${GCC_STABLE_VERSION} / C++latest" - command: "libcxx/utils/ci/run-buildbot generic-gcc" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "gcc-${GCC_STABLE_VERSION}" - CXX: "g++-${GCC_STABLE_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "C++26" - command: "libcxx/utils/ci/run-buildbot generic-cxx26" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note modules require and absolute path for clang-scan-deps - # https://github.com/llvm/llvm-project/issues/61006 - CC: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang" - CXX: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Modular build" - command: "libcxx/utils/ci/run-buildbot generic-modules" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "C++11" - command: "libcxx/utils/ci/run-buildbot generic-cxx11" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "C++03" - command: "libcxx/utils/ci/run-buildbot generic-cxx03" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # - # All other supported configurations of libc++. - # - - wait - - - label: "C++23" - command: "libcxx/utils/ci/run-buildbot generic-cxx23" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note: Modules require and absolute path for clang-scan-deps - # https://github.com/llvm/llvm-project/issues/61006 - CC: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang" - CXX: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - ENABLE_STD_MODULES: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "C++20" - command: "libcxx/utils/ci/run-buildbot generic-cxx20" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note: Modules require and absolute path for clang-scan-deps - # https://github.com/llvm/llvm-project/issues/61006 - CC: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang" - CXX: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - ENABLE_STD_MODULES: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "C++17" - command: "libcxx/utils/ci/run-buildbot generic-cxx17" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "C++14" - command: "libcxx/utils/ci/run-buildbot generic-cxx14" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Tests with the supported compilers. - - label: "GCC ${GCC_STABLE_VERSION} / C++11" - command: "libcxx/utils/ci/run-buildbot generic-gcc-cxx11" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "gcc-${GCC_STABLE_VERSION}" - CXX: "g++-${GCC_STABLE_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Clang 16" - command: "libcxx/utils/ci/run-buildbot generic-cxx23" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-16" - CXX: "clang++-16" - ENABLE_CLANG_TIDY: "On" - ENABLE_STD_MODULES: "Off" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Clang 17" - command: "libcxx/utils/ci/run-buildbot generic-cxx23" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note: Modules require and absolute path for clang-scan-deps - # https://github.com/llvm/llvm-project/issues/61006 - CC: "/usr/lib/llvm-17/bin/clang" - CXX: "/usr/lib/llvm-17/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Tests with the sanitizers. - - group: "Sanitizers" - steps: - - label: "ASAN" - command: "libcxx/utils/ci/run-buildbot generic-asan" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "TSAN" - command: "libcxx/utils/ci/run-buildbot generic-tsan" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "UBSAN" - command: "libcxx/utils/ci/run-buildbot generic-ubsan" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "MSAN" - command: "libcxx/utils/ci/run-buildbot generic-msan" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Tests with the various supported ways to build libc++. - - label: "Bootstrapping build" - command: "libcxx/utils/ci/run-buildbot bootstrapping-build" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - - "**/crash_diagnostics/*" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - LLVM_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer-${LLVM_HEAD_VERSION}" - CLANG_CRASH_DIAGNOSTICS_DIR: "crash_diagnostics" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Tests with various build configurations. - - label: "Static libraries" - command: "libcxx/utils/ci/run-buildbot generic-static" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Shared library with merged ABI and unwinder libraries" - command: "libcxx/utils/ci/run-buildbot generic-merged" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Hardened mode" - command: "libcxx/utils/ci/run-buildbot generic-hardened-mode" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Safe mode" - command: "libcxx/utils/ci/run-buildbot generic-safe-mode" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note: Modules require an absolute path for `clang-scan-deps` (see - # https://github.com/llvm/llvm-project/issues/61006). - CC: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang" - CXX: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Debug mode" - command: "libcxx/utils/ci/run-buildbot generic-debug-mode" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "With LLVM's libunwind" - command: "libcxx/utils/ci/run-buildbot generic-with_llvm_unwinder" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Modular build with Local Submodule Visibility" - command: "libcxx/utils/ci/run-buildbot generic-modules-lsv" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - group: "Parts disabled" - steps: - - label: "No threads" - command: "libcxx/utils/ci/run-buildbot generic-no-threads" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note: Modules require and absolute path for clang-scan-deps - # https://github.com/llvm/llvm-project/issues/61006 - CC: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang" - CXX: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No filesystem" - command: "libcxx/utils/ci/run-buildbot generic-no-filesystem" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note: Modules require and absolute path for clang-scan-deps - # https://github.com/llvm/llvm-project/issues/61006 - CC: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang" - CXX: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No random device" - command: "libcxx/utils/ci/run-buildbot generic-no-random_device" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note: Modules require and absolute path for clang-scan-deps - # https://github.com/llvm/llvm-project/issues/61006 - CC: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang" - CXX: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No locale" - command: "libcxx/utils/ci/run-buildbot generic-no-localization" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note: Modules require and absolute path for clang-scan-deps - # https://github.com/llvm/llvm-project/issues/61006 - CC: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang" - CXX: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No Unicode" - command: "libcxx/utils/ci/run-buildbot generic-no-unicode" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note: Modules require and absolute path for clang-scan-deps - # https://github.com/llvm/llvm-project/issues/61006 - CC: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang" - CXX: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No wide characters" - command: "libcxx/utils/ci/run-buildbot generic-no-wide-characters" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note: Modules require and absolute path for clang-scan-deps - # https://github.com/llvm/llvm-project/issues/61006 - CC: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang" - CXX: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No time zone database" - command: "libcxx/utils/ci/run-buildbot generic-no-tzdb" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No experimental features" - command: "libcxx/utils/ci/run-buildbot generic-no-experimental" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note: Modules require and absolute path for clang-scan-deps - # https://github.com/llvm/llvm-project/issues/61006 - CC: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang" - CXX: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "No exceptions" - command: "libcxx/utils/ci/run-buildbot generic-no-exceptions" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - # Note: Modules require and absolute path for clang-scan-deps - # https://github.com/llvm/llvm-project/issues/61006 - CC: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang" - CXX: "/usr/lib/llvm-${LLVM_HEAD_VERSION}/bin/clang++" - CMAKE: "/opt/bin/cmake" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Unstable ABI" - command: "libcxx/utils/ci/run-buildbot generic-abi-unstable" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Other non-testing CI jobs - - label: "Benchmarks" - command: "libcxx/utils/ci/run-buildbot benchmarks" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang-${LLVM_HEAD_VERSION}" - CXX: "clang++-${LLVM_HEAD_VERSION}" - ENABLE_CLANG_TIDY: "On" - agents: - queue: "libcxx-builders" - os: "linux" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - # Tests on non-Unix platforms - - group: ":windows: Windows" - steps: - - label: "Clang-cl (DLL)" - command: "bash libcxx/utils/ci/run-buildbot clang-cl-dll" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Clang-cl (Static)" - command: "bash libcxx/utils/ci/run-buildbot clang-cl-static" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Clang-cl (no vcruntime exceptions)" - command: "bash libcxx/utils/ci/run-buildbot clang-cl-no-vcruntime" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - - - label: "Clang-cl (Debug mode)" - command: "bash libcxx/utils/ci/run-buildbot clang-cl-debug" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Clang-cl (Static CRT)" - command: "bash libcxx/utils/ci/run-buildbot clang-cl-static-crt" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "MinGW (DLL, x86_64)" - command: "bash libcxx/utils/ci/run-buildbot mingw-dll" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "MinGW (Static, x86_64)" - command: "bash libcxx/utils/ci/run-buildbot mingw-static" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "MinGW (DLL, i686)" - command: "bash libcxx/utils/ci/run-buildbot mingw-dll-i686" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "windows" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - group: ":mac: Apple" steps: - label: "MacOS x86_64" @@ -991,147 +156,3 @@ - exit_status: -1 # Agent was lost limit: 2 timeout_in_minutes: 120 - - - group: "ARM" - steps: - - label: "AArch64" - command: "libcxx/utils/ci/run-buildbot aarch64" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders-linaro-arm" - arch: "aarch64" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "AArch64 -fno-exceptions" - command: "libcxx/utils/ci/run-buildbot aarch64-no-exceptions" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders-linaro-arm" - arch: "aarch64" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Armv8" - command: "libcxx/utils/ci/run-buildbot armv8" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders-linaro-arm" - arch: "armv8l" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Armv8 -fno-exceptions" - command: "libcxx/utils/ci/run-buildbot armv8-no-exceptions" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders-linaro-arm" - arch: "armv8l" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Armv7" - command: "libcxx/utils/ci/run-buildbot armv7" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders-linaro-arm" - arch: "armv8l" # Compiling for v7, running on v8 hardware - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "Armv7 -fno-exceptions" - command: "libcxx/utils/ci/run-buildbot armv7-no-exceptions" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - agents: - queue: "libcxx-builders-linaro-arm" - arch: "armv8l" # Compiling for v7, running on v8 hardware - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - group: "AIX" - steps: - - label: "AIX (32-bit)" - command: "libcxx/utils/ci/run-buildbot aix" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang" - CXX: "clang++" - OBJECT_MODE: "32" - agents: - queue: libcxx-builders - os: aix - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - label: "AIX (64-bit)" - command: "libcxx/utils/ci/run-buildbot aix" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang" - CXX: "clang++" - OBJECT_MODE: "64" - agents: - queue: libcxx-builders - os: aix - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120 - - - group: ":freebsd: FreeBSD" - steps: - - label: "FreeBSD 13 amd64" - command: "libcxx/utils/ci/run-buildbot generic-cxx23" - artifact_paths: - - "**/test-results.xml" - - "**/*.abilist" - env: - CC: "clang16" - CXX: "clang++16" - ENABLE_STD_MODULES: "Off" - agents: - queue: "libcxx-builders" - os: "freebsd" - retry: - automatic: - - exit_status: -1 # Agent was lost - limit: 2 - timeout_in_minutes: 120