1 /*
2 * Copyright 2016-2020 Max Kellermann <max.kellermann@gmail.com>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the
14 * distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 * OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #ifndef EXCEPTION_HXX
31 #define EXCEPTION_HXX
32
33 #include <exception>
34 #include <string>
35 #include <utility>
36
37 /**
38 * Throws the specified exception. There is an overload for
39 * std::exception_ptr which throws the contained exception instead of
40 * the std::exception_ptr itself.
41 */
42 template<typename T>
43 [[noreturn]]
44 inline void
ThrowException(T && t)45 ThrowException(T &&t)
46 {
47 throw std::forward<T>(t);
48 }
49
50 [[noreturn]]
51 inline void
ThrowException(std::exception_ptr ep)52 ThrowException(std::exception_ptr ep)
53 {
54 std::rethrow_exception(ep);
55 }
56
57 /**
58 * Create a nested exception, wrapping #ep inside the
59 * std::current_exception().
60 */
61 template<typename T>
62 inline std::exception_ptr
NestCurrentException(T && t)63 NestCurrentException(T &&t) noexcept
64 {
65 try {
66 std::throw_with_nested(std::forward<T>(t));
67 } catch (...) {
68 return std::current_exception();
69 }
70 }
71
72 /**
73 * Create a nested exception, wrapping #ep inside (a copy of) #t.
74 */
75 template<typename T>
76 inline std::exception_ptr
NestException(std::exception_ptr ep,T && t)77 NestException(std::exception_ptr ep, T &&t) noexcept
78 {
79 try {
80 std::rethrow_exception(ep);
81 } catch (...) {
82 return NestCurrentException(std::forward<T>(t));
83 }
84 }
85
86 /**
87 * Find an instance of #T in the nested exception chain, and rethrow
88 * it. Does nothing of no such instance was found.
89 */
90 template<typename T>
91 inline void
FindRetrowNested(std::exception_ptr ep)92 FindRetrowNested(std::exception_ptr ep)
93 {
94 try {
95 std::rethrow_exception(ep);
96 } catch (const T &t) {
97 throw;
98 } catch (const std::exception &e) {
99 try {
100 std::rethrow_if_nested(e);
101 } catch (...) {
102 FindRetrowNested<T>(std::current_exception());
103 }
104 } catch (const std::nested_exception &ne) {
105 FindRetrowNested<T>(ne.nested_ptr());
106 } catch (...) {
107 }
108 }
109
110 /**
111 * Obtain the full concatenated message of an exception and its nested
112 * chain.
113 */
114 std::string
115 GetFullMessage(const std::exception &e,
116 const char *fallback="Unknown exception",
117 const char *separator="; ") noexcept;
118
119 /**
120 * Obtain the full concatenated message of an exception and its nested
121 * chain.
122 */
123 std::string
124 GetFullMessage(std::exception_ptr ep,
125 const char *fallback="Unknown exception",
126 const char *separator="; ") noexcept;
127
128 #endif
129