Skip to content

Commit aade746

Browse files
committed
[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
1 parent a9138cd commit aade746

File tree

70 files changed

+2033
-843
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+2033
-843
lines changed

libcxx/include/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@ set(files
838838
__utility/cmp.h
839839
__utility/convert_to_integral.h
840840
__utility/declval.h
841+
__utility/empty.h
841842
__utility/exception_guard.h
842843
__utility/exchange.h
843844
__utility/forward.h
@@ -851,7 +852,6 @@ set(files
851852
__utility/priority_tag.h
852853
__utility/rel_ops.h
853854
__utility/swap.h
854-
__utility/terminate_on_exception.h
855855
__utility/to_underlying.h
856856
__utility/unreachable.h
857857
__variant/monostate.h

libcxx/include/__algorithm/pstl_any_all_none_of.h

+64-16
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#include <__type_traits/is_execution_policy.h>
1818
#include <__type_traits/remove_cvref.h>
1919
#include <__utility/move.h>
20-
#include <__utility/terminate_on_exception.h>
20+
#include <optional>
2121

2222
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2323
# pragma GCC system_header
@@ -35,19 +35,35 @@ template <class _ExecutionPolicy,
3535
class _Predicate,
3636
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
3737
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
38-
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
39-
any_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
40-
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
38+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool> __any_of(
39+
_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Predicate&& __pred) noexcept {
4140
return std::__pstl_frontend_dispatch(
4241
_LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_any_of, _RawPolicy),
43-
[&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) {
44-
return std::find_if(__policy, __g_first, __g_last, __g_pred) != __g_last;
42+
[&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) -> optional<bool> {
43+
auto __res = std::__find_if(__policy, __g_first, __g_last, __g_pred);
44+
if (!__res)
45+
return nullopt;
46+
return *__res != __g_last;
4547
},
4648
std::move(__first),
4749
std::move(__last),
4850
std::move(__pred));
4951
}
5052

53+
template <class _ExecutionPolicy,
54+
class _ForwardIterator,
55+
class _Predicate,
56+
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
57+
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
58+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
59+
any_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
60+
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
61+
auto __res = std::__any_of(__policy, std::move(__first), std::move(__last), std::move(__pred));
62+
if (!__res)
63+
std::__throw_bad_alloc();
64+
return *std::move(__res);
65+
}
66+
5167
template <class>
5268
void __pstl_all_of(); // declaration needed for the frontend dispatch below
5369

@@ -56,21 +72,37 @@ template <class _ExecutionPolicy,
5672
class _Pred,
5773
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
5874
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
59-
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
60-
all_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) {
61-
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
75+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
76+
__all_of(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Pred&& __pred) noexcept {
6277
return std::__pstl_frontend_dispatch(
6378
_LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_all_of, _RawPolicy),
64-
[&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) {
65-
return !std::any_of(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) {
79+
[&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) -> optional<bool> {
80+
auto __res = std::__any_of(__policy, __g_first, __g_last, [&](__iter_reference<_ForwardIterator> __value) {
6681
return !__g_pred(__value);
6782
});
83+
if (!__res)
84+
return nullopt;
85+
return !*__res;
6886
},
6987
std::move(__first),
7088
std::move(__last),
7189
std::move(__pred));
7290
}
7391

92+
template <class _ExecutionPolicy,
93+
class _ForwardIterator,
94+
class _Pred,
95+
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
96+
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
97+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
98+
all_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) {
99+
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
100+
auto __res = std::__all_of(__policy, std::move(__first), std::move(__last), std::move(__pred));
101+
if (!__res)
102+
std::__throw_bad_alloc();
103+
return *std::move(__res);
104+
}
105+
74106
template <class>
75107
void __pstl_none_of(); // declaration needed for the frontend dispatch below
76108

@@ -79,19 +111,35 @@ template <class _ExecutionPolicy,
79111
class _Pred,
80112
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
81113
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
82-
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
83-
none_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) {
84-
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
114+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
115+
__none_of(_ExecutionPolicy&& __policy, _ForwardIterator&& __first, _ForwardIterator&& __last, _Pred&& __pred) noexcept {
85116
return std::__pstl_frontend_dispatch(
86117
_LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_none_of, _RawPolicy),
87-
[&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) {
88-
return !std::any_of(__policy, __g_first, __g_last, __g_pred);
118+
[&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) -> optional<bool> {
119+
auto __res = std::__any_of(__policy, __g_first, __g_last, __g_pred);
120+
if (!__res)
121+
return nullopt;
122+
return !*__res;
89123
},
90124
std::move(__first),
91125
std::move(__last),
92126
std::move(__pred));
93127
}
94128

129+
template <class _ExecutionPolicy,
130+
class _ForwardIterator,
131+
class _Pred,
132+
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
133+
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
134+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool
135+
none_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) {
136+
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator);
137+
auto __res = std::__none_of(__policy, std::move(__first), std::move(__last), std::move(__pred));
138+
if (!__res)
139+
std::__throw_bad_alloc();
140+
return *std::move(__res);
141+
}
142+
95143
_LIBCPP_END_NAMESPACE_STD
96144

97145
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

libcxx/include/__algorithm/pstl_backend.h

+71-65
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@ TODO: Documentation of how backends work
2727
A PSTL parallel backend is a tag type to which the following functions are associated, at minimum:
2828
2929
template <class _ExecutionPolicy, class _Iterator, class _Func>
30-
void __pstl_for_each(_Backend, _ExecutionPolicy&&, _Iterator __first, _Iterator __last, _Func __f);
30+
optional<__empty> __pstl_for_each(_Backend, _ExecutionPolicy&&, _Iterator __first, _Iterator __last, _Func __f);
3131
3232
template <class _ExecutionPolicy, class _Iterator, class _Predicate>
33-
_Iterator __pstl_find_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
33+
optional<_Iterator> __pstl_find_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
3434
3535
template <class _ExecutionPolicy, class _RandomAccessIterator, class _Comp>
36-
void __pstl_stable_sort(_Backend, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp);
36+
optional<__empty>
37+
__pstl_stable_sort(_Backend, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp);
3738
3839
template <class _ExecutionPolicy,
3940
class _ForwardIterator1,
@@ -49,42 +50,38 @@ A PSTL parallel backend is a tag type to which the following functions are assoc
4950
_Comp __comp);
5051
5152
template <class _ExecutionPolicy, class _InIterator, class _OutIterator, class _UnaryOperation>
52-
_OutIterator __pstl_transform(_Backend,
53-
_InIterator __first,
54-
_InIterator __last,
55-
_OutIterator __result,
56-
_UnaryOperation __op);
53+
optional<_OutIterator>
54+
__pstl_transform(_Backend, _InIterator __first, _InIterator __last, _OutIterator __result, _UnaryOperation __op);
5755
5856
template <class _ExecutionPolicy, class _InIterator1, class _InIterator2, class _OutIterator, class _BinaryOperation>
59-
_OutIterator __pstl_transform(_Backend,
60-
_InIterator1 __first1,
61-
_InIterator1 __last1,
62-
_InIterator2 __first2,
63-
_OutIterator __result,
64-
_BinaryOperation __op);
57+
optional<_OutIterator> __pstl_transform(_InIterator1 __first1,
58+
_InIterator2 __first2,
59+
_InIterator1 __last1,
60+
_OutIterator __result,
61+
_BinaryOperation __op);
6562
6663
template <class _ExecutionPolicy,
6764
class _Iterator1,
6865
class _Iterator2,
6966
class _Tp,
7067
class _BinaryOperation1,
7168
class _BinaryOperation2>
72-
_Tp __pstl_transform_reduce(_Backend,
73-
_Iterator1 __first1,
74-
_Iterator1 __last1,
75-
_Iterator2 __first2,
76-
_Iterator2 __last2,
77-
_Tp __init,
78-
_BinaryOperation1 __reduce,
79-
_BinaryOperation2 __transform);
69+
optional<_Tp> __pstl_transform_reduce(_Backend,
70+
_Iterator1 __first1,
71+
_Iterator1 __last1,
72+
_Iterator2 __first2,
73+
_Iterator2 __last2,
74+
_Tp __init,
75+
_BinaryOperation1 __reduce,
76+
_BinaryOperation2 __transform);
8077
8178
template <class _ExecutionPolicy, class _Iterator, class _Tp, class _BinaryOperation, class _UnaryOperation>
82-
_Tp __pstl_transform_reduce(_Backend,
83-
_Iterator __first,
84-
_Iterator __last,
85-
_Tp __init,
86-
_BinaryOperation __reduce,
87-
_UnaryOperation __transform);
79+
optional<_Tp> __pstl_transform_reduce(_Backend,
80+
_Iterator __first,
81+
_Iterator __last,
82+
_Tp __init,
83+
_BinaryOperation __reduce,
84+
_UnaryOperation __transform);
8885
8986
// TODO: Complete this list
9087
@@ -93,86 +90,95 @@ algorithms, otherwise they are implemented in terms of other algorithms. If none
9390
implemented, all the algorithms will eventually forward to the basis algorithms listed above:
9491
9592
template <class _ExecutionPolicy, class _Iterator, class _Size, class _Func>
96-
void __pstl_for_each_n(_Backend, _Iterator __first, _Size __n, _Func __f);
93+
optional<__empty> __pstl_for_each_n(_Backend, _Iterator __first, _Size __n, _Func __f);
9794
9895
template <class _ExecutionPolicy, class _Iterator, class _Predicate>
99-
bool __pstl_any_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
96+
optional<bool> __pstl_any_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
10097
10198
template <class _ExecutionPolicy, class _Iterator, class _Predicate>
102-
bool __pstl_all_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
99+
optional<bool> __pstl_all_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
103100
104101
template <class _ExecutionPolicy, class _Iterator, class _Predicate>
105-
bool __pstl_none_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
102+
optional<bool> __pstl_none_of(_Backend, _Iterator __first, _iterator __last, _Predicate __pred);
106103
107104
template <class _ExecutionPolicy, class _Iterator, class _Tp>
108-
_Iterator __pstl_find(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
105+
optional<_Iterator> __pstl_find(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
109106
110107
template <class _ExecutionPolicy, class _Iterator, class _Predicate>
111-
_Iterator __pstl_find_if_not(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
108+
optional<_Iterator> __pstl_find_if_not(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
112109
113110
template <class _ExecutionPolicy, class _Iterator, class _Tp>
114-
void __pstl_fill(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
111+
optional<__empty> __pstl_fill(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
115112
116113
template <class _ExecutionPolicy, class _Iterator, class _SizeT, class _Tp>
117-
void __pstl_fill_n(_Backend, _Iterator __first, _SizeT __n, const _Tp& __value);
114+
optional<__empty> __pstl_fill_n(_Backend, _Iterator __first, _SizeT __n, const _Tp& __value);
118115
119116
template <class _ExecutionPolicy, class _Iterator, class _Generator>
120-
void __pstl_generate(_Backend, _Iterator __first, _Iterator __last, _Generator __gen);
117+
optional<__empty> __pstl_generate(_Backend, _Iterator __first, _Iterator __last, _Generator __gen);
121118
122119
template <class _ExecutionPolicy, class _Iterator, class _Predicate>
123-
void __pstl_is_partitioned(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
120+
optional<__empty> __pstl_is_partitioned(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
124121
125122
template <class _ExecutionPolicy, class _Iterator, class _Size, class _Generator>
126-
void __pstl_generator_n(_Backend, _Iterator __first, _Size __n, _Generator __gen);
123+
optional<__empty> __pstl_generator_n(_Backend, _Iterator __first, _Size __n, _Generator __gen);
127124
128125
template <class _ExecutionPolicy, class _terator1, class _Iterator2, class _OutIterator, class _Comp>
129-
_OutIterator __pstl_merge(_Backend,
130-
_Iterator1 __first1,
131-
_Iterator1 __last1,
132-
_Iterator2 __first2,
133-
_Iterator2 __last2,
134-
_OutIterator __result,
135-
_Comp __comp);
126+
optional<_OutIterator> __pstl_merge(_Backend,
127+
_Iterator1 __first1,
128+
_Iterator1 __last1,
129+
_Iterator2 __first2,
130+
_Iterator2 __last2,
131+
_OutIterator __result,
132+
_Comp __comp);
136133
137134
template <class _ExecutionPolicy, class _Iterator, class _Tp, class _BinaryOperation>
138-
_Tp __pstl_reduce(_Backend, _Iterator __first, _Iterator __last, _Tp __init, _BinaryOperation __op);
135+
optional<_Tp> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last, _Tp __init, _BinaryOperation __op);
139136
140137
temlate <class _ExecutionPolicy, class _Iterator>
141-
__iter_value_type<_Iterator> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last);
138+
optional<__iter_value_type<_Iterator>> __pstl_reduce(_Backend, _Iterator __first, _Iterator __last);
142139
143140
template <class _ExecuitonPolicy, class _Iterator, class _Tp>
144-
__iter_diff_t<_Iterator> __pstl_count(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
141+
optional<__iter_diff_t<_Iterator>> __pstl_count(_Backend, _Iterator __first, _Iterator __last, const _Tp& __value);
145142
146143
template <class _ExecutionPolicy, class _Iterator, class _Predicate>
147-
__iter_diff_t<_Iterator> __pstl_count_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
144+
optional<__iter_diff_t<_Iterator>> __pstl_count_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
148145
149146
template <class _ExecutionPolicy, class _Iterator, class _Tp>
150-
void __pstl_replace(_Backend, _Iterator __first, _Iterator __last, const _Tp& __old_value, const _Tp& __new_value);
147+
optional<__empty>
148+
__pstl_replace(_Backend, _Iterator __first, _Iterator __last, const _Tp& __old_value, const _Tp& __new_value);
151149
152150
template <class _ExecutionPolicy, class _Iterator, class _Pred, class _Tp>
153-
void __pstl_replace_if(_Backend, _Iterator __first, _Iterator __last, _Pred __pred, const _Tp& __new_value);
151+
optional<__empty>
152+
__pstl_replace_if(_Backend, _Iterator __first, _Iterator __last, _Pred __pred, const _Tp& __new_value);
154153
155154
template <class _ExecutionPolicy, class _Iterator, class _OutIterator, class _Tp>
156-
void __pstl_replace_copy(_Backend,
157-
_Iterator __first,
158-
_Iterator __last,
159-
_OutIterator __result,
160-
const _Tp& __old_value,
161-
const _Tp& __new_value);
155+
optional<__empty> __pstl_replace_copy(_Backend,
156+
_Iterator __first,
157+
_Iterator __last,
158+
_OutIterator __result,
159+
const _Tp& __old_value,
160+
const _Tp& __new_value);
162161
163162
template <class _ExecutionPolicy, class _Iterator, class _OutIterator, class _Pred, class _Tp>
164-
void __pstl_replace_copy_if(_Backend,
165-
_Iterator __first,
166-
_Iterator __last,
167-
_OutIterator __result,
168-
_Pred __pred,
169-
const _Tp& __new_value);
163+
optional<__empty> __pstl_replace_copy_if(_Backend,
164+
_Iterator __first,
165+
_Iterator __last,
166+
_OutIterator __result,
167+
_Pred __pred,
168+
const _Tp& __new_value);
170169
171170
template <class _ExecutionPolicy, class _Iterator, class _Comp>
172-
void __pstl_sort(_Backend, _Iterator __first, _Iterator __last, _Comp __comp);
171+
optional<__empty> __pstl_sort(_Backend, _Iterator __first, _Iterator __last, _Comp __comp);
173172
174173
// TODO: Complete this list
175174
175+
Exception handling
176+
==================
177+
178+
PSTL backends are expected to report errors (i.e. failure to allocate) by returning a disengaged `optional` from their
179+
implementation. Exceptions shouldn't be used to report an internal failure-to-allocate, since all exceptions are turned
180+
into a program termination at the front-end level. When a backend returns a disengaged `optional` to the frontend, the
181+
frontend will turn that into a call to `std::__throw_bad_alloc();` to report the internal failure to the user.
176182
*/
177183

178184
template <class _ExecutionPolicy>

0 commit comments

Comments
 (0)