]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | #ifndef BOOST_LEAF_EXCEPTION_HPP_INCLUDED |
2 | #define BOOST_LEAF_EXCEPTION_HPP_INCLUDED | |
3 | ||
1e59de90 | 4 | // Copyright 2018-2022 Emil Dotchevski and Reverge Studios, Inc. |
20effc67 TL |
5 | |
6 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
7 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
8 | ||
1e59de90 | 9 | #include <boost/leaf/config.hpp> |
20effc67 | 10 | #include <boost/leaf/error.hpp> |
1e59de90 TL |
11 | |
12 | #ifndef BOOST_LEAF_NO_EXCEPTIONS | |
13 | ||
20effc67 TL |
14 | #include <exception> |
15 | ||
16 | #define BOOST_LEAF_EXCEPTION ::boost::leaf::leaf_detail::inject_loc{__FILE__,__LINE__,__FUNCTION__}+::boost::leaf::exception | |
17 | #define BOOST_LEAF_THROW_EXCEPTION ::boost::leaf::leaf_detail::throw_with_loc{__FILE__,__LINE__,__FUNCTION__}+::boost::leaf::exception | |
18 | ||
19 | //////////////////////////////////////// | |
20 | ||
21 | namespace boost { namespace leaf { | |
22 | ||
1e59de90 TL |
23 | namespace leaf_detail |
24 | { | |
25 | struct throw_with_loc | |
20effc67 | 26 | { |
1e59de90 TL |
27 | char const * const file; |
28 | int const line; | |
29 | char const * const fn; | |
30 | ||
31 | template <class Ex> | |
32 | [[noreturn]] friend void operator+( throw_with_loc loc, Ex const & ex ) | |
20effc67 | 33 | { |
1e59de90 TL |
34 | ex.load_source_location_(loc.file, loc.line, loc.fn); |
35 | ::boost::leaf::throw_exception(ex); | |
36 | } | |
37 | }; | |
38 | } | |
20effc67 TL |
39 | |
40 | } } | |
41 | ||
42 | //////////////////////////////////////// | |
43 | ||
44 | namespace boost { namespace leaf { | |
45 | ||
1e59de90 TL |
46 | namespace leaf_detail |
47 | { | |
48 | inline void enforce_std_exception( std::exception const & ) noexcept { } | |
49 | ||
50 | class BOOST_LEAF_SYMBOL_VISIBLE exception_base | |
20effc67 | 51 | { |
1e59de90 TL |
52 | std::shared_ptr<void const> auto_id_bump_; |
53 | public: | |
54 | ||
55 | virtual error_id get_error_id() const noexcept = 0; | |
20effc67 | 56 | |
1e59de90 TL |
57 | protected: |
58 | ||
59 | exception_base(): | |
60 | auto_id_bump_(0, [](void const *) { (void) new_id(); }) | |
20effc67 | 61 | { |
1e59de90 | 62 | } |
20effc67 | 63 | |
1e59de90 TL |
64 | ~exception_base() noexcept { } |
65 | }; | |
20effc67 | 66 | |
1e59de90 TL |
67 | template <class Ex> |
68 | class BOOST_LEAF_SYMBOL_VISIBLE exception: | |
69 | public Ex, | |
70 | public exception_base, | |
71 | public error_id | |
72 | { | |
73 | error_id get_error_id() const noexcept final override | |
74 | { | |
75 | return *this; | |
76 | } | |
20effc67 | 77 | |
1e59de90 | 78 | public: |
20effc67 | 79 | |
1e59de90 TL |
80 | exception( exception const & ) = default; |
81 | exception( exception && ) = default; | |
20effc67 | 82 | |
1e59de90 TL |
83 | BOOST_LEAF_CONSTEXPR exception( error_id id, Ex const & ex ) noexcept: |
84 | Ex(ex), | |
85 | error_id(id) | |
20effc67 | 86 | { |
1e59de90 TL |
87 | enforce_std_exception(*this); |
88 | } | |
89 | ||
90 | BOOST_LEAF_CONSTEXPR exception( error_id id, Ex && ex ) noexcept: | |
91 | Ex(std::move(ex)), | |
92 | error_id(id) | |
20effc67 | 93 | { |
1e59de90 TL |
94 | enforce_std_exception(*this); |
95 | } | |
96 | ||
97 | explicit BOOST_LEAF_CONSTEXPR exception( error_id id ) noexcept: | |
98 | error_id(id) | |
99 | { | |
100 | enforce_std_exception(*this); | |
101 | } | |
102 | }; | |
103 | ||
104 | template <class... T> | |
105 | struct at_least_one_derives_from_std_exception; | |
20effc67 | 106 | |
1e59de90 TL |
107 | template <> |
108 | struct at_least_one_derives_from_std_exception<>: std::false_type { }; | |
109 | ||
110 | template <class T, class... Rest> | |
111 | struct at_least_one_derives_from_std_exception<T, Rest...> | |
20effc67 | 112 | { |
1e59de90 TL |
113 | constexpr static const bool value = std::is_base_of<std::exception,typename std::remove_reference<T>::type>::value || at_least_one_derives_from_std_exception<Rest...>::value; |
114 | }; | |
115 | } | |
116 | ||
117 | template <class Ex, class... E> | |
118 | inline | |
119 | typename std::enable_if<std::is_base_of<std::exception,typename std::remove_reference<Ex>::type>::value, leaf_detail::exception<typename std::remove_reference<Ex>::type>>::type | |
120 | exception( error_id err, Ex && ex, E && ... e ) noexcept | |
121 | { | |
122 | static_assert(!leaf_detail::at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception"); | |
123 | return leaf_detail::exception<typename std::remove_reference<Ex>::type>( err.load(std::forward<E>(e)...), std::forward<Ex>(ex) ); | |
124 | } | |
125 | ||
126 | template <class E1, class... E> | |
127 | inline | |
128 | typename std::enable_if<!std::is_base_of<std::exception,typename std::remove_reference<E1>::type>::value, leaf_detail::exception<std::exception>>::type | |
129 | exception( error_id err, E1 && car, E && ... cdr ) noexcept | |
130 | { | |
131 | static_assert(!leaf_detail::at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception"); | |
132 | return leaf_detail::exception<std::exception>( err.load(std::forward<E1>(car), std::forward<E>(cdr)...) ); | |
133 | } | |
134 | ||
135 | inline leaf_detail::exception<std::exception> exception( error_id err ) noexcept | |
136 | { | |
137 | return leaf_detail::exception<std::exception>(err); | |
138 | } | |
139 | ||
140 | template <class Ex, class... E> | |
141 | inline | |
142 | typename std::enable_if<std::is_base_of<std::exception,typename std::remove_reference<Ex>::type>::value, leaf_detail::exception<typename std::remove_reference<Ex>::type>>::type | |
143 | exception( Ex && ex, E && ... e ) noexcept | |
144 | { | |
145 | static_assert(!leaf_detail::at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception"); | |
146 | return leaf_detail::exception<typename std::remove_reference<Ex>::type>( new_error().load(std::forward<E>(e)...), std::forward<Ex>(ex) ); | |
147 | } | |
148 | ||
149 | template <class E1, class... E> | |
150 | inline | |
151 | typename std::enable_if<!std::is_base_of<std::exception,typename std::remove_reference<E1>::type>::value, leaf_detail::exception<std::exception>>::type | |
152 | exception( E1 && car, E && ... cdr ) noexcept | |
153 | { | |
154 | static_assert(!leaf_detail::at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception"); | |
155 | return leaf_detail::exception<std::exception>( new_error().load(std::forward<E1>(car), std::forward<E>(cdr)...) ); | |
156 | } | |
157 | ||
158 | inline leaf_detail::exception<std::exception> exception() noexcept | |
159 | { | |
160 | return leaf_detail::exception<std::exception>(leaf::new_error()); | |
161 | } | |
162 | ||
163 | //////////////////////////////////////// | |
164 | ||
165 | #ifndef BOOST_LEAF_NO_EXCEPTIONS | |
166 | ||
167 | template <class T> | |
168 | class result; | |
169 | ||
170 | namespace leaf_detail | |
171 | { | |
172 | inline error_id catch_exceptions_helper( std::exception const & ex, leaf_detail_mp11::mp_list<> ) | |
173 | { | |
174 | return leaf::new_error(std::current_exception()); | |
20effc67 TL |
175 | } |
176 | ||
1e59de90 TL |
177 | template <class Ex1, class... Ex> |
178 | inline error_id catch_exceptions_helper( std::exception const & ex, leaf_detail_mp11::mp_list<Ex1,Ex...> ) | |
20effc67 | 179 | { |
1e59de90 TL |
180 | if( Ex1 const * p = dynamic_cast<Ex1 const *>(&ex) ) |
181 | return catch_exceptions_helper(ex, leaf_detail_mp11::mp_list<Ex...>{ }).load(*p); | |
182 | else | |
183 | return catch_exceptions_helper(ex, leaf_detail_mp11::mp_list<Ex...>{ }); | |
20effc67 TL |
184 | } |
185 | ||
1e59de90 TL |
186 | template <class T> |
187 | struct deduce_exception_to_result_return_type_impl | |
188 | { | |
189 | using type = result<T>; | |
190 | }; | |
191 | ||
192 | template <class T> | |
193 | struct deduce_exception_to_result_return_type_impl<result<T>> | |
20effc67 | 194 | { |
1e59de90 TL |
195 | using type = result<T>; |
196 | }; | |
197 | ||
198 | template <class T> | |
199 | using deduce_exception_to_result_return_type = typename deduce_exception_to_result_return_type_impl<T>::type; | |
200 | } | |
201 | ||
202 | template <class... Ex, class F> | |
203 | inline | |
204 | leaf_detail::deduce_exception_to_result_return_type<leaf_detail::fn_return_type<F>> | |
205 | exception_to_result( F && f ) noexcept | |
206 | { | |
207 | try | |
208 | { | |
209 | return std::forward<F>(f)(); | |
210 | } | |
211 | catch( std::exception const & ex ) | |
212 | { | |
213 | return leaf_detail::catch_exceptions_helper(ex, leaf_detail_mp11::mp_list<Ex...>()); | |
214 | } | |
215 | catch(...) | |
216 | { | |
217 | return leaf::new_error(std::current_exception()); | |
20effc67 | 218 | } |
1e59de90 TL |
219 | } |
220 | ||
221 | #endif | |
20effc67 TL |
222 | |
223 | } } | |
224 | ||
225 | #endif | |
1e59de90 TL |
226 | |
227 | #endif |