[libcxx-commits] [libcxx] aade746 - [libc++][PSTL] Overhaul exceptions handling
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Oct 6 14:01:35 PDT 2023
Author: Nikolas Klauser
Date: 2023-10-06T23:01:30+02:00
New Revision: aade74675c15d3bae5fdfa67f7b4b6ed9dac3d20
URL: https://github.com/llvm/llvm-project/commit/aade74675c15d3bae5fdfa67f7b4b6ed9dac3d20
DIFF: https://github.com/llvm/llvm-project/commit/aade74675c15d3bae5fdfa67f7b4b6ed9dac3d20.diff
LOG: [libc++][PSTL] Overhaul exceptions handling
This makes exception handling a lot simpler, since we don't have to convert any exceptions this way. Is also properly handles all the user-thrown exceptions.
Reviewed By: ldionne, #libc
Spies: arichardson, mstorsjo, libcxx-commits
Differential Revision: https://reviews.llvm.org/D154238
Added:
libcxx/include/__utility/empty.h
libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.exception_handling.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.exception_handling.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/pstl.exception_handling.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.exception_handling.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.exception_handling.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.exception_handling.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.exception_handling.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.exception_handling.pass.cpp
libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.exception_handling.pass.cpp
libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.exception_handling.pass.cpp
libcxx/test/std/algorithms/numeric.ops/reduce/pstl.exception_handling.pass.cpp
libcxx/test/std/algorithms/numeric.ops/transform.reduce/pstl.exception_handling.pass.cpp
Modified:
libcxx/include/CMakeLists.txt
libcxx/include/__algorithm/pstl_any_all_none_of.h
libcxx/include/__algorithm/pstl_backend.h
libcxx/include/__algorithm/pstl_backends/cpu_backend.h
libcxx/include/__algorithm/pstl_backends/cpu_backends/any_of.h
libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h
libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h
libcxx/include/__algorithm/pstl_backends/cpu_backends/for_each.h
libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h
libcxx/include/__algorithm/pstl_backends/cpu_backends/merge.h
libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h
libcxx/include/__algorithm/pstl_backends/cpu_backends/stable_sort.h
libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h
libcxx/include/__algorithm/pstl_backends/cpu_backends/transform.h
libcxx/include/__algorithm/pstl_backends/cpu_backends/transform_reduce.h
libcxx/include/__algorithm/pstl_copy.h
libcxx/include/__algorithm/pstl_count.h
libcxx/include/__algorithm/pstl_fill.h
libcxx/include/__algorithm/pstl_find.h
libcxx/include/__algorithm/pstl_for_each.h
libcxx/include/__algorithm/pstl_generate.h
libcxx/include/__algorithm/pstl_is_partitioned.h
libcxx/include/__algorithm/pstl_merge.h
libcxx/include/__algorithm/pstl_replace.h
libcxx/include/__algorithm/pstl_sort.h
libcxx/include/__algorithm/pstl_stable_sort.h
libcxx/include/__algorithm/pstl_transform.h
libcxx/include/__numeric/pstl_reduce.h
libcxx/include/__numeric/pstl_transform_reduce.h
libcxx/include/module.modulemap.in
libcxx/test/libcxx/algorithms/pstl.robust_against_customization_points_not_working.pass.cpp
libcxx/test/libcxx/transitive_includes/cxx03.csv
libcxx/test/libcxx/transitive_includes/cxx11.csv
libcxx/test/libcxx/transitive_includes/cxx14.csv
libcxx/test/libcxx/transitive_includes/cxx17.csv
libcxx/test/libcxx/transitive_includes/cxx20.csv
libcxx/test/libcxx/transitive_includes/cxx23.csv
libcxx/test/libcxx/transitive_includes/cxx26.csv
libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/pstl.fill_n.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.all_of/pstl.all_of.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.any_of/pstl.any_of.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.foreach/pstl.for_each_n.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.none_of/pstl.none_of.pass.cpp
libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/pstl.stable_sort.pass.cpp
libcxx/test/support/check_assertion.h
libcxx/test/support/test_execution_policies.h
libcxx/test/support/test_iterators.h
Removed:
libcxx/include/__utility/terminate_on_exception.h
################################################################################
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 2ec755236dbaee2..340353f8ebb41c4 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -838,6 +838,7 @@ set(files
__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 @@ set(files
__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
index 47d280c4314938b..d93fdba2224c9b1 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -35,19 +35,35 @@ template <class _ExecutionPolicy,
class _Predicate,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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<bool> __any_of(
+ _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept {
return std::__pstl_frontend_dispatch(
_LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_any_of, _RawPolicy),
- [&](_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<bool> {
+ 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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Predicate,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class>
void __pstl_all_of(); // declaration needed for the frontend dispatch below
@@ -56,21 +72,37 @@ template <class _ExecutionPolicy,
class _Pred,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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<bool>
+__all_of(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Pred&& __pred) noexcept {
return std::__pstl_frontend_dispatch(
_LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_all_of, _RawPolicy),
- [&](_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<bool> {
+ 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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Pred,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class>
void __pstl_none_of(); // declaration needed for the frontend dispatch below
@@ -79,19 +111,35 @@ template <class _ExecutionPolicy,
class _Pred,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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<bool>
+__none_of(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Pred&& __pred) noexcept {
return std::__pstl_frontend_dispatch(
_LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_none_of, _RawPolicy),
- [&](_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<bool> {
+ 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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Pred,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index 3d9459ef5fa23a4..94644e5c47b3952 100644
--- a/libcxx/include/__algorithm/pstl_backend.h
+++ b/libcxx/include/__algorithm/pstl_backend.h
@@ -27,13 +27,14 @@ TODO: Documentation of how backends work
A PSTL parallel backend is a tag type to which the following functions are associated, at minimum:
template <class _ExecutionPolicy, class _Iterator, class _Func>
- 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 <class _ExecutionPolicy, class _Iterator, class _Predicate>
- _Iterator __pstl_find_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
+ optional<_Iterator> __pstl_find_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
template <class _ExecutionPolicy, class _RandomAccessIterator, class _Comp>
- void __pstl_stable_sort(_Backend, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp);
+ optional<__empty>
+ __pstl_stable_sort(_Backend, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp);
template <class _ExecutionPolicy,
class _ForwardIterator1,
@@ -49,19 +50,15 @@ A PSTL parallel backend is a tag type to which the following functions are assoc
_Comp __comp);
template <class _ExecutionPolicy, class _InIterator, class _OutIterator, class _UnaryOperation>
- _OutIterator __pstl_transform(_Backend,
- _InIterator __first,
- _InIterator __last,
- _OutIterator __result,
- _UnaryOperation __op);
+ optional<_OutIterator>
+ __pstl_transform(_Backend, _InIterator __first, _InIterator __last, _OutIterator __result, _UnaryOperation __op);
template <class _ExecutionPolicy, class _InIterator1, class _InIterator2, class _OutIterator, class _BinaryOperation>
- _OutIterator __pstl_transform(_Backend,
- _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 <class _ExecutionPolicy,
class _Iterator1,
@@ -69,22 +66,22 @@ A PSTL parallel backend is a tag type to which the following functions are assoc
class _Tp,
class _BinaryOperation1,
class _BinaryOperation2>
- _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 <class _ExecutionPolicy, class _Iterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
- _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
@@ -93,86 +90,95 @@ algorithms, otherwise they are implemented in terms of other algorithms. If none
implemented, all the algorithms will eventually forward to the basis algorithms listed above:
template <class _ExecutionPolicy, class _Iterator, class _Size, class _Func>
- 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 <class _ExecutionPolicy, class _Iterator, class _Predicate>
- bool __pstl_any_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
+ optional<bool> __pstl_any_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
template <class _ExecutionPolicy, class _Iterator, class _Predicate>
- bool __pstl_all_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
+ optional<bool> __pstl_all_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
template <class _ExecutionPolicy, class _Iterator, class _Predicate>
- bool __pstl_none_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
+ optional<bool> __pstl_none_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
template <class _ExecutionPolicy, class _Iterator, class _Tp>
- _Iterator __pstl_find(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
+ optional<_Iterator> __pstl_find(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
template <class _ExecutionPolicy, class _Iterator, class _Predicate>
- _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 <class _ExecutionPolicy, class _Iterator, class _Tp>
- void __pstl_fill(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
+ optional<__empty> __pstl_fill(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
template <class _ExecutionPolicy, class _Iterator, class _SizeT, class _Tp>
- 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 <class _ExecutionPolicy, class _Iterator, class _Generator>
- void __pstl_generate(_Backend, _Iterator __first, _Iterator __last, _Generator __gen);
+ optional<__empty> __pstl_generate(_Backend, _Iterator __first, _Iterator __last, _Generator __gen);
template <class _ExecutionPolicy, class _Iterator, class _Predicate>
- void __pstl_is_partitioned(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
+ optional<__empty> __pstl_is_partitioned(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
template <class _ExecutionPolicy, class _Iterator, class _Size, class _Generator>
- void __pstl_generator_n(_Backend, _Iterator __first, _Size __n, _Generator __gen);
+ optional<__empty> __pstl_generator_n(_Backend, _Iterator __first, _Size __n, _Generator __gen);
template <class _ExecutionPolicy, class _terator1, class _Iterator2, class _OutIterator, class _Comp>
- _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 <class _ExecutionPolicy, class _Iterator, class _Tp, class _BinaryOperation>
- _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 <class _ExecutionPolicy, class _Iterator>
- __iter_value_type<_Iterator> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last);
+ optional<__iter_value_type<_Iterator>> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last);
template <class _ExecuitonPolicy, class _Iterator, class _Tp>
- __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 <class _ExecutionPolicy, class _Iterator, class _Predicate>
- __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 <class _ExecutionPolicy, class _Iterator, class _Tp>
- 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 <class _ExecutionPolicy, class _Iterator, class _Pred, class _Tp>
- 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 <class _ExecutionPolicy, class _Iterator, class _OutIterator, class _Tp>
- 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 <class _ExecutionPolicy, class _Iterator, class _OutIterator, class _Pred, class _Tp>
- 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 <class _ExecutionPolicy, class _Iterator, class _Comp>
- 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 <class _ExecutionPolicy>
diff --git a/libcxx/include/__algorithm/pstl_backends/cpu_backend.h b/libcxx/include/__algorithm/pstl_backends/cpu_backend.h
index e54f331b9430b68..6980ded189ea2a3 100644
--- 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 <class _RandomAccessIterator, class _Functor>
- void __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func);
+ optional<__empty> __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func);
template <class _Iterator, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduction>
- _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<void> __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
index c8a071af82ac699..13dff80086e72b2 100644
--- 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 <cstdint>
+#include <optional>
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
+_LIBCPP_PUSH_MACROS
+# include <__undef_macros>
+
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Index, class _Brick>
-_LIBCPP_HIDE_FROM_ABI bool __parallel_or(_Index __first, _Index __last, _Brick __f) {
+_LIBCPP_HIDE_FROM_ABI optional<bool> __parallel_or(_Index __first, _Index __last, _Brick __f) {
std::atomic<bool> __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<bool>(__found);
}
// TODO: check whether __simd_first() can be used here
@@ -64,17 +70,17 @@ _LIBCPP_HIDE_FROM_ABI bool __simd_or(_Index __first, _DifferenceType __n, _Pred
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
-_LIBCPP_HIDE_FROM_ABI bool
+_LIBCPP_HIDE_FROM_ABI optional<bool>
__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 @@ __pstl_any_of(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __la
_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
index 8b531887c731808..64babe9fd2bdae8 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -34,22 +35,23 @@ _LIBCPP_HIDE_FROM_ABI _Index __simd_fill_n(_Index __first, _DifferenceType __n,
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
-_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
index 91610c040857b79..170470e4fb7edde 100644
--- 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 <cstddef>
+#include <optional>
#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 <class _Index, class _Brick, class _Compare>
-_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>::
diff erence_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 <class _Index, class _DifferenceType, class _Compare>
@@ -91,21 +98,21 @@ __simd_first(_Index __first, _DifferenceType __begin, _DifferenceType __end, _Co
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
-_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 @@ __pstl_find_if(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __l
_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
index f6f22fdd8713ced..6cfef932aa48db3 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -34,22 +35,23 @@ _LIBCPP_HIDE_FROM_ABI _Iterator __simd_walk_1(_Iterator __first, _DifferenceType
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Functor>
-_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
index 50b6e0b1d0a03f3..e885e7f225172cc 100644
--- 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 <cstddef>
#include <new>
+#include <optional>
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
@@ -61,8 +63,9 @@ struct __chunk_partitions {
[[__gnu__::__const__]] _LIBCPP_EXPORTED_FROM_ABI __chunk_partitions __partition_chunks(ptr
diff _t __size) noexcept;
template <class _RandomAccessIterator, class _Functor>
-_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 @@ __dispatch_parallel_for(__chunk_partitions __partitions, _RandomAccessIterator _
: (__chunk * __partitions.__chunk_size_) + (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
__func(__first + __index, __first + __index + __this_chunk_size);
});
+
+ return __empty{};
}
template <class _RandomAccessIterator, class _Functor>
-_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 @@ template <typename _RandomAccessIterator1,
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<ptr
diff _t>(__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 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_merge(
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 (ptr
diff _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 (ptr
diff _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 <class _RandomAccessIterator, class _Transform, class _Value, class _Combiner, class _Reduction>
-_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 @@ _LIBCPP_HIDE_FROM_ABI _Value __parallel_transform_reduce(
}
});
- 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 <class _RandomAccessIterator, class _Comp, class _LeafSort>
-_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 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_stable_sort(
// 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
index c4b28e95024ff5b..b0db70f58b2ef48 100644
--- 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 <optional>
#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 <class _ExecutionPolicy,
@@ -30,7 +33,7 @@ template <class _ExecutionPolicy,
class _ForwardIterator2,
class _ForwardOutIterator,
class _Comp>
-_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 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_merge(
__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_HIDE_FROM_ABI _ForwardOutIterator __pstl_merge(
_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
index f151c3b098f6748..afcc7ffb2661304 100644
--- 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 <cstddef>
+#include <optional>
#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 <class _RandomAccessIterator, class _Fp>
-_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 <class _Index, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduce>
-_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 <class _RandomAccessIterator, class _Compare, class _LeafSort>
-_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 @@ template <class _RandomAccessIterator1,
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 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_merge(
_Compare __comp,
_LeafMerge __leaf_merge) {
__leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp);
+ return __empty{};
}
// TODO: Complete this list
@@ -67,6 +76,8 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_merge(
_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
index 0a701443b3c40c6..34c423586c4b742 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -24,17 +25,16 @@
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _ExecutionPolicy, class _RandomAccessIterator, class _Comp>
-_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
index 30eb0ae3626d47a..eb11a961b760c30 100644
--- 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 <cstddef>
+#include <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -32,20 +34,23 @@ namespace __par_backend {
inline namespace __thread_cpu_backend {
template <class _RandomAccessIterator, class _Fp>
-_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 <class _Index, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduce>
-_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 <class _RandomAccessIterator, class _Compare, class _LeafSort>
-_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 @@ template <class _RandomAccessIterator1,
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 @@ _LIBCPP_HIDE_FROM_ABI void __parallel_merge(
_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
index 0259d8a84bb3f76..2c7647d61a2b0a4 100644
--- 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 <optional>
#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 <class _Iterator1, class _DifferenceType, class _Iterator2, class _Function>
@@ -37,7 +40,7 @@ __simd_walk_2(_Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Fu
}
template <class _ExecutionPolicy, class _ForwardIterator, class _ForwardOutIterator, class _UnaryOperation>
-_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 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform(
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 @@ template <class _ExecutionPolicy,
class _ForwardOutIterator,
class _BinaryOperation,
enable_if_t<is_execution_policy_v<__remove_cvref_t<_ExecutionPolicy>>, 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 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform(
__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_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform(
_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
index 2afe5c7d10483fe..a5ca9c89d1ab23b 100644
--- 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 <new>
+#include <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -98,7 +98,7 @@ template <class _ExecutionPolicy,
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 @@ _LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce(
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 @@ _LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce(
}
template <class _ExecutionPolicy, class _ForwardIterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
-_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 @@ _LIBCPP_HIDE_FROM_ABI _Tp __pstl_transform_reduce(
_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
index e4a6e5a54e48e79..19f275a0d5d97fc 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -41,18 +42,34 @@ template <class _ExecutionPolicy,
class _ForwardOutIterator,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
[&__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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _ForwardOutIterator,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class>
void __pstl_copy_n();
@@ -62,21 +79,36 @@ template <class _ExecutionPolicy,
class _Size,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
- [&__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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _ForwardOutIterator,
+ class _Size,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index cc1e82457006cf8..28806fca0637013 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -41,13 +41,13 @@ template <class _ExecutionPolicy,
class _Predicate,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
- [&](_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 @@ count_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator
std::move(__pred));
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Predicate,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class>
void __pstl_count(); // declaration needed for the frontend dispatch below
@@ -68,11 +81,12 @@ template <class _ExecutionPolicy,
class _Tp,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
- [&](_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 @@ count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __
__value);
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Tp,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index fc817b5c9e6ea75..3057dcc04f1ad74 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -38,13 +38,13 @@ template <class _ExecutionPolicy,
class _Tp,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
[&](_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 @@ fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __l
__value);
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Tp,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class>
void __pstl_fill_n(); // declaration needed for the frontend dispatch below
@@ -62,22 +74,36 @@ template <class _ExecutionPolicy,
class _Tp,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
[&](_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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _SizeT,
+ class _Tp,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index c2894d08752ef27..adc05ea1a9e55a0 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -34,13 +34,26 @@ template <class _ExecutionPolicy,
class _Predicate,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Predicate,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class>
void __pstl_find_if_not();
@@ -49,21 +62,36 @@ template <class _ExecutionPolicy,
class _Predicate,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
- [&](_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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Predicate,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class>
void __pstl_find();
@@ -72,21 +100,35 @@ template <class _ExecutionPolicy,
class _Tp,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
- [&](_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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Tp,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index 6e6c73d19f6fec7..819a43d685abed5 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -31,16 +32,27 @@
_LIBCPP_BEGIN_NAMESPACE_STD
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Function,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class _ExecutionPolicy,
class _ForwardIterator,
class _Function,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class>
@@ -52,23 +64,38 @@ template <class _ExecutionPolicy,
class _Function,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
- [&](_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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Size,
+ class _Function,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index 9a70e2e26bbf975..56538392d5b5ddd 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -36,13 +37,13 @@ template <class _ExecutionPolicy,
class _Generator,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
[&__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 @@ generate(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator
std::move(__gen));
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Generator,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class>
void __pstl_generate_n();
@@ -61,21 +74,34 @@ template <class _ExecutionPolicy,
class _Generator,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
[&__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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Size,
+ class _Generator,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index 1492ce212742d47..39cf6369339db69 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -35,8 +36,8 @@ template <class _ExecutionPolicy,
class _Predicate,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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<bool> __is_partitioned(
+ _ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) {
return std::__pstl_frontend_dispatch(
_LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_is_partitioned, _RawPolicy),
[&__policy](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) {
@@ -51,6 +52,19 @@ is_partitioned(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIt
std::move(__pred));
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Predicate,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index f10ac7674282874..ed8014510863266 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -25,6 +26,32 @@
_LIBCPP_BEGIN_NAMESPACE_STD
+template <class _ExecutionPolicy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _ForwardOutIterator,
+ class _Comp = std::less<>,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class _ExecutionPolicy,
class _ForwardIterator1,
class _ForwardIterator2,
@@ -33,22 +60,24 @@ template <class _ExecutionPolicy,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index 08f59ce2deab85d..05dee3f6a4f30c6 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -36,19 +37,21 @@ template <class _ExecutionPolicy,
class _Tp,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
- [&__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 @@ replace_if(_ExecutionPolicy&& __policy,
__new_value);
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Pred,
+ class _Tp,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class>
void __pstl_replace();
@@ -64,17 +84,17 @@ template <class _ExecutionPolicy,
class _Tp,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
[&__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 @@ replace(_ExecutionPolicy&& __policy,
__new_value);
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Tp,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class>
void __pstl_replace_copy_if();
@@ -97,23 +132,26 @@ template <class _ExecutionPolicy,
class _Tp,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
[&__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 @@ _LIBCPP_HIDE_FROM_ABI void replace_copy_if(
__new_value);
}
-template <class>
-void __pstl_replace_copy();
-
template <class _ExecutionPolicy,
class _ForwardIterator,
class _ForwardOutIterator,
+ class _Pred,
class _Tp,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class>
+void __pstl_replace_copy();
+
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _ForwardOutIterator,
+ class _Tp,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
[&__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 @@ _LIBCPP_HIDE_FROM_ABI void replace_copy(
__new_value);
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _ForwardOutIterator,
+ class _Tp,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index 85239df0abebe3f..3e71e0aa5ae0a1c 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -35,18 +37,30 @@ template <class _ExecutionPolicy,
class _Comp,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
[&__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 <class _ExecutionPolicy,
+ class _RandomAccessIterator,
+ class _Comp,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class _ExecutionPolicy,
class _RandomAccessIterator,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
diff --git a/libcxx/include/__algorithm/pstl_stable_sort.h b/libcxx/include/__algorithm/pstl_stable_sort.h
index 510ffd862980dcd..c9d375535fc4505 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -30,10 +32,21 @@ template <class _ExecutionPolicy,
class _Comp = less<>,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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 _ExecutionPolicy,
+ class _RandomAccessIterator,
+ class _Comp = less<>,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index a34439304a8fdd0..aad59d1f30e6b93 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -26,6 +26,23 @@
_LIBCPP_BEGIN_NAMESPACE_STD
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _ForwardOutIterator,
+ class _UnaryOperation,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class _ExecutionPolicy,
class _ForwardIterator,
class _ForwardOutIterator,
@@ -33,7 +50,7 @@ template <class _ExecutionPolicy,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
- _ExecutionPolicy&&,
+ _ExecutionPolicy&& __policy,
_ForwardIterator __first,
_ForwardIterator __last,
_ForwardOutIterator __result,
@@ -41,9 +58,29 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
_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 <class _ExecutionPolicy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _ForwardOutIterator,
+ class _BinaryOperation,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class _ExecutionPolicy,
@@ -54,7 +91,7 @@ template <class _ExecutionPolicy,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
- _ExecutionPolicy&&,
+ _ExecutionPolicy&& __policy,
_ForwardIterator1 __first1,
_ForwardIterator1 __last1,
_ForwardIterator2 __first2,
@@ -64,9 +101,11 @@ _LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
_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
index 22ef2707d7d3eea..b19972a46db7fac 100644
--- a/libcxx/include/__numeric/pstl_reduce.h
+++ b/libcxx/include/__numeric/pstl_reduce.h
@@ -33,16 +33,16 @@ template <class _ExecutionPolicy,
class _BinaryOperation = plus<>,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
[&__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 @@ reduce(_ExecutionPolicy&& __policy,
template <class _ExecutionPolicy,
class _ForwardIterator,
+ class _Tp,
+ class _BinaryOperation = plus<>,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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, _RawPolicy),
[&__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 <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index b7c9d8d288f99c2..4127ee21e3045c8 100644
--- 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 <optional>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -34,23 +34,53 @@ template <class _ExecutionPolicy,
class _BinaryOperation2,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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 <class _ExecutionPolicy,
+ class _ForwardIterator1,
+ class _ForwardIterator2,
+ class _Tp,
+ class _BinaryOperation1,
+ class _BinaryOperation2,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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 @@ template <class _ExecutionPolicy,
class _UnaryOperation,
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
enable_if_t<is_execution_policy_v<_RawPolicy>, 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 @@ _LIBCPP_HIDE_FROM_ABI _Tp transform_reduce(
std::move(__transform));
}
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Tp,
+ class _BinaryOperation,
+ class _UnaryOperation,
+ class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
+ enable_if_t<is_execution_policy_v<_RawPolicy>, 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
index 000000000000000..8cca197145c7235
--- /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
index e035ec3409ae529..000000000000000
--- 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 <new>
-
-#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 <class _Func>
-_LIBCPP_HIDE_FROM_ABI auto __terminate_on_exception(_Func __func) {
- try {
- return __func();
- } catch (...) {
- std::terminate();
- }
-}
-
-# else // _LIBCPP_HAS_NO_EXCEPTIONS
-
-template <class _Func>
-_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
index 6d9bb8653fcb5e9..26657b78b8440c6 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2053,6 +2053,7 @@ module std_private_utility_cmp [system] {
}
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 @@ module std_private_utility_swap [system] {
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
index 89349d1610d0d0e..e3733bf468da4d4 100644
--- 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 <cassert>
+#include <optional>
struct TestPolicy {};
struct TestBackend {};
@@ -27,7 +29,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
bool pstl_any_of_called = false;
template <class, class ForwardIterator, class Pred>
-bool __pstl_any_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
+optional<bool> __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_any_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
bool pstl_all_of_called = false;
template <class, class ForwardIterator, class Pred>
-bool __pstl_all_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
+optional<bool> __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_all_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
bool pstl_copy_called = false;
template <class, class ForwardIterator, class ForwardOutIterator>
-ForwardIterator __pstl_copy(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator) {
+optional<ForwardOutIterator> __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 <class, class ForwardIterator, class Size, class ForwardOutIterator>
-ForwardIterator __pstl_copy_n(TestBackend, ForwardIterator, Size, ForwardOutIterator) {
+optional<ForwardOutIterator> __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 <class, class ForwardIterator, class T>
-typename std::iterator_traits<ForwardIterator>::
diff erence_type
+optional<typename std::iterator_traits<ForwardIterator>::
diff erence_type>
__pstl_count(TestBackend, ForwardIterator, ForwardIterator, const T&) {
assert(!pstl_count_called);
pstl_count_called = true;
@@ -73,7 +75,7 @@ __pstl_count(TestBackend, ForwardIterator, ForwardIterator, const T&) {
bool pstl_count_if_called = false;
template <class, class ForwardIterator, class Pred>
-typename std::iterator_traits<ForwardIterator>::
diff erence_type
+optional<typename std::iterator_traits<ForwardIterator>::
diff erence_type>
__pstl_count_if(TestBackend, ForwardIterator, ForwardIterator, Pred) {
assert(!pstl_count_if_called);
pstl_count_if_called = true;
@@ -83,23 +85,25 @@ __pstl_count_if(TestBackend, ForwardIterator, ForwardIterator, Pred) {
bool pstl_generate_called = false;
template <class, class ForwardIterator, class Gen>
-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 <class, class ForwardIterator, class Size, class Gen>
-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 <class, class ForwardIterator, class Pred>
-bool __pstl_none_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
+optional<bool> __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_none_of(TestBackend, ForwardIterator, ForwardIterator, Pred) {
bool pstl_find_called = false;
template <class, class ForwardIterator, class Pred>
-ForwardIterator __pstl_find(TestBackend, ForwardIterator, ForwardIterator, Pred) {
+optional<ForwardIterator> __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 <class, class ForwardIterator, class Pred>
-ForwardIterator __pstl_find_if(TestBackend, ForwardIterator, ForwardIterator, Pred) {
+optional<ForwardIterator> __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 <class, class ForwardIterator, class Pred>
-ForwardIterator __pstl_find_if_not(TestBackend, ForwardIterator, ForwardIterator, Pred) {
+optional<ForwardIterator> __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 <class, class ForwardIterator, class Size, class Func>
-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 <class, class ForwardIterator, class Size, class Func>
-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 <class, class ForwardIterator, class Size, class Func>
-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 <class, class ForwardIterator, class Size, class Func>
-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 <class, class ForwardIterator, class Func>
-bool __pstl_is_partitioned(TestBackend, ForwardIterator, ForwardIterator, Func) {
+optional<bool> __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 <class, class ForwardIterator, class T>
-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 <class, class ForwardIterator, class T, class Func>
-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 <class, class ForwardIterator, class ForwardOutIterator, class T>
-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 <class, class ForwardIterator, class ForwardOutIterator, class T, class Func>
-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 <class, class ForwardIterator, class ForwardOutIterator, class UnaryOperation>
-ForwardOutIterator __pstl_transform(TestBackend, ForwardIterator, ForwardIterator, ForwardOutIterator, UnaryOperation) {
+optional<ForwardOutIterator>
+__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 <class, class ForwardIterator1, class ForwardIterator2, class ForwardOutIterator, class BinaryOperation>
-ForwardOutIterator __pstl_transform(
- TestBackend, ForwardIterator1, ForwardIterator1, ForwardIterator2, ForwardOutIterator, BinaryOperation) {
+optional<ForwardOutIterator> __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 <class, class ForwardIterator, class T, class BinaryOperation>
-T __pstl_reduce(TestBackend, ForwardIterator, ForwardIterator, T, BinaryOperation) {
+optional<T> __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 <class, class ForwardIterator>
-typename std::iterator_traits<ForwardIterator>::value_type
-__pstl_reduce(TestBackend, ForwardIterator, ForwardIterator) {
+optional<typename std::iterator_traits<ForwardIterator>::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 <class, class RandomAccessIterator, class Comp>
-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 <class, class RandomAccessIterator, class Comp>
-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 <class, class ForwardIterator, class T, class UnaryOperation, class BinaryOperation>
-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 @@ template <class,
class BinaryOperation1,
class BinaryOperation2>
typename std::iterator_traits<ForwardIterator1>::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
index 70dbad21780a1c7..f6aeb837a7292f6 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -6,7 +6,6 @@ algorithm cstddef
algorithm cstdint
algorithm cstdlib
algorithm cstring
-algorithm ctime
algorithm cwchar
algorithm execution
algorithm initializer_list
@@ -15,7 +14,7 @@ algorithm iterator
algorithm limits
algorithm memory
algorithm new
-algorithm ratio
+algorithm optional
algorithm stdexcept
algorithm type_traits
algorithm utility
@@ -585,15 +584,12 @@ numeric cmath
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
index 1ee950f9fc30ea2..08fd94393f47320 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -6,7 +6,6 @@ algorithm cstddef
algorithm cstdint
algorithm cstdlib
algorithm cstring
-algorithm ctime
algorithm cwchar
algorithm execution
algorithm initializer_list
@@ -15,7 +14,7 @@ algorithm iterator
algorithm limits
algorithm memory
algorithm new
-algorithm ratio
+algorithm optional
algorithm stdexcept
algorithm type_traits
algorithm utility
@@ -590,15 +589,12 @@ numeric cmath
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
index 22e1d30f7fd67b2..33384a628e65c01 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -6,7 +6,6 @@ algorithm cstddef
algorithm cstdint
algorithm cstdlib
algorithm cstring
-algorithm ctime
algorithm cwchar
algorithm execution
algorithm initializer_list
@@ -15,7 +14,7 @@ algorithm iterator
algorithm limits
algorithm memory
algorithm new
-algorithm ratio
+algorithm optional
algorithm stdexcept
algorithm type_traits
algorithm utility
@@ -592,15 +591,12 @@ numeric cmath
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
index 22e1d30f7fd67b2..33384a628e65c01 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -6,7 +6,6 @@ algorithm cstddef
algorithm cstdint
algorithm cstdlib
algorithm cstring
-algorithm ctime
algorithm cwchar
algorithm execution
algorithm initializer_list
@@ -15,7 +14,7 @@ algorithm iterator
algorithm limits
algorithm memory
algorithm new
-algorithm ratio
+algorithm optional
algorithm stdexcept
algorithm type_traits
algorithm utility
@@ -592,15 +591,12 @@ numeric cmath
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
index 0cbd4c52c6e4c9b..8f6e8dd646df583 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -6,7 +6,6 @@ algorithm cstddef
algorithm cstdint
algorithm cstdlib
algorithm cstring
-algorithm ctime
algorithm cwchar
algorithm execution
algorithm initializer_list
@@ -15,7 +14,7 @@ algorithm iterator
algorithm limits
algorithm memory
algorithm new
-algorithm ratio
+algorithm optional
algorithm stdexcept
algorithm type_traits
algorithm utility
@@ -597,15 +596,12 @@ numeric cmath
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
index 8b32cad73fb5ada..d0d858056b1b00d 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -9,6 +9,7 @@ algorithm initializer_list
algorithm iosfwd
algorithm limits
algorithm new
+algorithm optional
algorithm ratio
algorithm version
any cstddef
@@ -432,6 +433,7 @@ numeric execution
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
index 8b32cad73fb5ada..d0d858056b1b00d 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -9,6 +9,7 @@ algorithm initializer_list
algorithm iosfwd
algorithm limits
algorithm new
+algorithm optional
algorithm ratio
algorithm version
any cstddef
@@ -432,6 +433,7 @@ numeric execution
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
index 000000000000000..f7279655cb129f9
--- /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 <algorithm>
+
+#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
index a341816b10b6ee7..556326fb0894cab 100644
--- 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 @@ struct Test {
}
};
-#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<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index 594ac6a44bef448..4abbd6f7a17c3d4 100644
--- 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 @@ struct Test {
}
};
-#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<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index 000000000000000..98fde95fb0e441f
--- /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 <algorithm>
+
+#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
index 0b51d35cdeb99f9..751d6b74b0128a3 100644
--- 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 Test {
}
};
-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<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index 29c9692e0307aed..f24bedabebccdf9 100644
--- 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 Test {
}
};
-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<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index 965cedb91c4e1db..f7c746f382d117f 100644
--- 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 Test {
}
};
-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<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index 2f81955a029d64f..3ffc1c021bb9ce9 100644
--- 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 Test {
}
};
-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<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index 000000000000000..6c7149f4048ade8
--- /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 <algorithm>
+
+#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
index 82ba4338886d696..a3af9b949bfd2e4 100644
--- 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 @@ struct Test {
int main(int, char**) {
types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index 000000000000000..cc62979835361b6
--- /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 <algorithm>
+
+#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
index c21ce8afe556bc2..229bf576dd80136 100644
--- 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 @@ struct Test {
int main(int, char**) {
types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index 000000000000000..167c4ac4df95e3f
--- /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 <algorithm>
+
+#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
index 000000000000000..06b0810c257b3f6
--- /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 <algorithm>
+
+#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
index 9822ffbff8b03f8..8a9eee81d95c06f 100644
--- 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 Test {
}
};
-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<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index c67868ccc8881bd..49eef2a7bc55f71 100644
--- 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 @@ struct Test {
int main(int, char**) {
types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index d536249f6f1e20a..e5a242c57a2c4a0 100644
--- 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 @@ struct Test {
int main(int, char**) {
types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index 000000000000000..ab15bdf5d8b99be
--- /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 <algorithm>
+
+#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
index 4f70c1be3074576..b0e77094f0a4242 100644
--- 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 @@ struct Test {
int main(int, char**) {
types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index 4efe19944183ef8..d5b42966b00007c 100644
--- 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 @@ struct Test {
int main(int, char**) {
types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index 000000000000000..9a6d8d636200cf8
--- /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 <algorithm>
+
+#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
index f6dfe0cbf7b3dea..fb3e34a2bdec3d2 100644
--- 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 @@ struct Test {
int main(int, char**) {
types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
-#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
index 000000000000000..b56959809829b87
--- /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 <algorithm>
+
+#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
index 000000000000000..43ee937a8a185e5
--- /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 <algorithm>
+
+#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
index 0c4dda5b03ca5cb..e1a64f5185b5d4e 100644
--- 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 @@ int main(int, char**) {
types::random_access_iterator_list<NotDefaultConstructible*>>{},
TestIteratorWithPolicies<Test>{});
-#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
index 000000000000000..65a112774ff7627
--- /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 <numeric>
+
+#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
index 000000000000000..d2df251d5c8ad59
--- /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 <numeric>
+
+#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
index 741dc4a78828a6f..98dd95b11556e6c 100644
--- a/libcxx/test/support/check_assertion.h
+++ b/libcxx/test/support/check_assertion.h
@@ -14,6 +14,7 @@
#include <cstddef>
#include <cstdio>
#include <cstdlib>
+#include <exception>
#include <string>
#include <string_view>
#include <utility>
@@ -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 @@ inline AssertionInfoMatcher& GlobalMatcher() {
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 @@ struct DeathTest {
CASE(RK_SetupFailure);
CASE(RK_MatchFound);
CASE(RK_Unknown);
+ CASE(RK_Terminate);
}
return "not a result kind";
}
@@ -236,6 +234,7 @@ struct DeathTest {
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 @@ void std::__libcpp_verbose_abort(char const* format, ...) {
}
std::exit(DeathTest::RK_MatchFailure);
}
+#endif // _LIBCPP_VERSION
+
+[[noreturn]] inline void terminate_handler() {
+ std::exit(DeathTest::RK_Terminate);
+}
template <class Func>
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 @@ inline bool ExpectDeath(const char* stmt, Func&& func, AssertionInfoMatcher Matc
};
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 @@ inline bool ExpectDeath(const char* stmt, Func&& func) {
/// 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
index df2ce94c7cc912f..65569bbec0836bf 100644
--- a/libcxx/test/support/test_execution_policies.h
+++ b/libcxx/test/support/test_execution_policies.h
@@ -58,8 +58,4 @@ struct Bool {
}
};
-#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
index f0e19fc3d5e628d..1133b9597d09cfb 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -1420,6 +1420,125 @@ ProxyRange(R&&) -> ProxyRange<std::views::all_t<R&&>>;
#endif // TEST_STD_VER > 17
+#if TEST_STD_VER >= 17
+
+namespace util {
+template <class Derived, class Iter>
+class iterator_wrapper {
+ Iter iter_;
+
+ using iter_traits = std::iterator_traits<Iter>;
+
+public:
+ using iterator_cateory = typename iter_traits::iterator_category;
+ using value_type = typename iter_traits::value_type;
+ using
diff erence_type = typename iter_traits::
diff erence_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[](
diff erence_type v) const {
+ return iter_[v];
+ }
+
+ Derived& operator++() {
+ ++iter_;
+ return static_cast<Derived&>(*this);
+ }
+
+ Derived operator++(int) {
+ auto tmp = static_cast<Derived&>(*this);
+ ++(*this);
+ return tmp;
+ }
+
+ Derived& operator--() {
+ --iter_;
+ return static_cast<Derived&>(*this);
+ }
+
+ Derived operator--(int) {
+ auto tmp = static_cast<Derived&>(*this);
+ --(*this);
+ return tmp;
+ }
+
+ iterator_wrapper& operator+=(
diff erence_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-(Derived iter,
diff erence_type i) {
+ iter.iter_ -= i;
+ return iter;
+ }
+
+ friend Derived operator+(Derived iter,
diff erence_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 Iter>
+class throw_on_move_iterator : public iterator_wrapper<throw_on_move_iterator<Iter>, Iter> {
+ using base = iterator_wrapper<throw_on_move_iterator<Iter>, Iter>;
+
+ int moves_until_throw_ = 0;
+
+public:
+ using
diff erence_type = typename base::
diff erence_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<base&>(*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 <class Iter>
+throw_on_move_iterator(Iter) -> throw_on_move_iterator<Iter>;
+#endif // TEST_HAS_NO_EXCEPTIONS
+} // namespace util
+
+#endif // TEST_STD_VER >= 17
+
namespace types {
template <class Ptr>
using random_access_iterator_list =
More information about the libcxx-commits
mailing list