MySQL 9.6.0
Source Code Documentation
call_and_catch.h
Go to the documentation of this file.
1// Copyright (c) 2024, 2025, Oracle and/or its affiliates.
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License, version 2.0,
5// as published by the Free Software Foundation.
6//
7// This program is designed to work with certain software (including
8// but not limited to OpenSSL) that is licensed under separate terms,
9// as designated in a particular file or component or in included license
10// documentation. The authors of MySQL hereby grant you an additional
11// permission to link the program and your derivative works with the
12// separately licensed software that they have either included with
13// the program or referenced in the documentation.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License, version 2.0, for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23
24#ifndef MYSQL_UTILS_CALL_AND_CATCH_H
25#define MYSQL_UTILS_CALL_AND_CATCH_H
26
27/// @file
28/// Experimental API header
29
30#include <concepts> // invocable
31#include <functional> // reference_wrapper
32#include <optional> // optional
33#include <type_traits> // conditional_t
34#include "mysql/utils/return_status.h" // Return_status
35
36/// @addtogroup GroupLibsMysqlUtils
37/// @{
38
39namespace mysql::utils {
40
41/// The return type for any call_and_catch(f, args...) call where f(args...)
42/// returns Type.
43/// @cond DOXYGEN_DOES_NOT_UNDERSTAND_THIS
44template <class Type>
45using Call_and_catch_type = std::conditional_t<
46 std::same_as<Type, void>,
47 Return_status, // void -> Return_status
48 std::optional<std::conditional_t<
49 std::is_reference_v<Type>,
50 // T & -> optional<reference_wrapper<T>>
51 std::reference_wrapper<std::remove_reference_t<Type>>,
52 // T -> optional<T>
53 Type>>>;
54/// @endcond
55
56/// Calls a function, catches exceptions from it, and wraps the exception status
57/// in the return value.
58///
59/// @param function Any function, possibly throwing.
60///
61/// @param args Parameters passed to the function.
62///
63/// @return If `function` is declared `noexcept`, this is equivalent to calling
64/// `function` directly and returning the result. Otherwise, if `function`
65/// returns void, this function returns mysql::utils::Return_status: `error`
66/// indicates out-of-memory and `ok` indicates success. Otherwise, if `function`
67/// returns a non-reference type, say `T`, this function returns
68/// `std::optional<T>`, which stores the return value on success, and uses no
69/// value on out-of-memory. Otherwise, `function` returns a reference type, say
70/// `T &`, this function returns `std::optional<std::reference_wrapper<T>>`,
71/// which holds a wrapper around the returned reference on success, and holds no
72/// value on error.
73template <class Function_t, class... Args_t>
74 requires std::invocable<Function_t, Args_t...>
75[[nodiscard]] decltype(auto) call_and_catch(const Function_t &function,
76 Args_t &&...args) noexcept {
77 auto call_function = [&]() -> decltype(auto) {
78 return function(std::forward<Args_t>(args)...);
79 };
80 using Return_t = decltype(call_function());
81 if constexpr (noexcept(function(std::forward<Args_t>(args)...))) {
82 return call_function();
83 } else if constexpr (std::same_as<Return_t, void>) {
84 try {
85 call_function();
86 return Return_status::ok;
87 } catch (...) {
89 }
90 } else {
91 try {
92 if constexpr (std::is_reference_v<Return_t>)
93 return std::make_optional(std::ref(call_function()));
94 else
95 return std::make_optional(call_function());
96 } catch (...) {
97 return Call_and_catch_type<Return_t>();
98 }
99 }
100}
101
102/// Whether `conditional_call_and_catch` should be enabled or not.
103// NOLINTNEXTLINE(performance-enum-size): silence clang-tidy's pointless hint
104enum class Shall_catch { no, yes };
105
106/// Call `function`, and if `shall_catch` is true, catch exceptions and wrap
107/// them in the return value. Otherwise, just call the function and return what
108/// the function returns.
109///
110/// @see call_and_catch
111template <Shall_catch shall_catch, class Function_t, class... Args_t>
112[[nodiscard]] decltype(auto) conditional_call_and_catch(
113 const Function_t &function,
114 Args_t &&...args) // this comment helps clang-format
115 noexcept(noexcept(function(std::forward<Args_t>(args)...)) ||
116 shall_catch == Shall_catch::yes) {
117 if constexpr (shall_catch == Shall_catch::yes) {
118 return call_and_catch(function, std::forward<Args_t>(args)...);
119 } else {
120 return function(std::forward<Args_t>(args)...);
121 }
122}
123
124/// Helper macro to define a function that returns the result of a single
125/// expression, and has a conditional noexcept clause deduced from whether that
126/// expression is noexcept or not. This expands to
127/// `noexcept(noexcept(X)) { return (X); }`.
128///
129/// @code
130/// class C { /*...*/ };
131///
132/// // for rvalue reference C, f never throws
133/// void f(C &&) noexcept {}
134///
135/// // for const lvalue reference C, f may throw (maybe it needs to allocate)
136/// void f(const C &) {}
137///
138/// // Call f(t). If f(t) may throw, catch any exceptions and return
139/// // Call_and_catch_type<decltype(f(t))>. If f(t) is noexcept, just return
140/// // what f(t) returned.
141/// template <class T>
142/// auto wrap_f(T &&t) {
143/// return call_and_catch(
144/// [&]() DEDUCED_NOEXCEPT_FUNCTION(f(std::forward<T>(t))));
145/// }
146/// @endcode
147///
148/// See also Boost's BOOST_HOF_RETURNS.
149// Can't avoid macro here
150// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
151#define DEDUCED_NOEXCEPT_FUNCTION(X) \
152 noexcept(noexcept(X)) { return (X); }
153
154} // namespace mysql::utils
155
156// addtogroup GroupLibsMysqlUtils
157/// @}
158
159#endif // ifndef MYSQL_UTILS_CALL_AND_CATCH_H
PT & ref(PT *tp)
Definition: tablespace_impl.cc:359
MediaType
Definition: media_type.h:33
Definition: gtid_format.h:47
decltype(call_function()) Return_t
Definition: call_and_catch.h:80
Return_status
Simple, strongly-typed enumeration to indicate internal status: ok, error.
Definition: return_status.h:40
@ ok
operation succeeded
@ error
operation failed
decltype(auto) conditional_call_and_catch(const Function_t &function, Args_t &&...args) noexcept(noexcept(function(std::forward< Args_t >(args)...))||shall_catch==Shall_catch::yes)
Call function, and if shall_catch is true, catch exceptions and wrap them in the return value.
Definition: call_and_catch.h:112
Experimental API header.