9#include "min-cpp-version/cpp17.h"
10#define GHPL_LATEST_MSVC_VERSION_WITH_EXPECTED_BUGS 1942
11#if __has_include(<expected>) && (!defined(_MSC_VER) || _MSC_VER > GHPL_LATEST_MSVC_VERSION_WITH_EXPECTED_BUGS) && defined(__cpp_lib_expected) && __cpp_lib_expected >= 202202L
16 using std::unexpected;
18#elif __has_include(<tl/expected.hpp>)
19#include <tl/expected.hpp>
25#elif defined(GHPL_EXPECTED_HEADER)
26#include GHPL_EXPECTED_HEADER
28#error "No expected implementation found"
36 constexpr bool is_expected_f(type_identity<T>) {
return false; }
37 template <
typename E,
typename V>
38 constexpr bool is_expected_f(type_identity<expected<V, E>> e) {
return true; }
41 constexpr auto expected_error_type(type_identity<T>) {
return type_identity<void>{}; }
42 template <
typename E,
typename V>
43 constexpr auto expected_error_type(type_identity<expected<V, E>> e) {
return type_identity<E>{}; }
46 using error_type_t =
typename decltype(expected_error_type(type_identity<T>{}))::type;
47 static_assert(std::is_same_v<error_type_t<expected<int, bool>>,
bool>);
51 constexpr bool is_expected = detail::is_expected_f(type_identity<remove_cvref_t<T>>{});
52 template <
typename E,
typename T>
53 constexpr bool is_expected_with_error = detail::is_expected_f(type_identity<T>{}) && std::is_same_v<detail::error_type_t<T>, E>;
54 static_assert(is_expected<expected<bool, int>>);
55 static_assert(is_expected_with_error<int, expected<bool, int>>);
59 template <
typename FUNC,
typename... ARGS>
60 inline auto call_with_expected_ec(FUNC&& func, ARGS&&... args)
noexcept(
noexcept(func(std::forward<ARGS>(args)...)))
61 -> expected<std::invoke_result_t<FUNC, ARGS&&...>, std::error_code>
64 if constexpr (std::is_void_v<std::invoke_result_t<FUNC, ARGS&&...>>)
66 func(std::forward<ARGS>(args)..., ec);
68 return unexpected(ec);
73 auto result = func(std::forward<ARGS>(args)..., ec);
75 return unexpected(ec);
81 struct undroppable final
83 template <
typename... ARGS,
typename = std::enable_if_t<std::is_constructible_v<T, ARGS...>>>
84 undroppable(ARGS&&... args)
noexcept(std::is_nothrow_constructible_v<T, ARGS...>)
85 : m_value(std::forward<ARGS>(args)...)
89 undroppable(undroppable
const& other)
noexcept(std::is_nothrow_copy_constructible_v<T>) =
default;
90 undroppable& operator=(undroppable
const& other)
noexcept(std::is_nothrow_copy_assignable_v<T>) =
default;
91 undroppable(undroppable&& other)
noexcept(std::is_nothrow_move_constructible_v<T>) =
default;
92 undroppable& operator=(undroppable&& other)
noexcept(std::is_nothrow_move_assignable_v<T>) =
default;
96 return std::exchange(m_value, {}).value();
99 bool was_handled() const noexcept {
return !m_value.has_value(); }
101 T
const& value() const noexcept {
return m_value.value(); }
102 T& value() noexcept {
return m_value.value(); }
104 ~undroppable() noexcept(false)
107 throw std::move(m_value.value());
112 std::optional<T> m_value;
116#define TOKEN_PASTE(x, y) x ## y
117#define TOKEN_PASTE2(x, y) TOKEN_PASTE(x, y)
118#define OR_RETURN_VAL TOKEN_PASTE2(_return_val_, __LINE__)
119#define or_return(exp) if (decltype(auto) OR_RETURN_VAL = (exp); !OR_RETURN_VAL.has_value()) return ::ghassanpl::unexpected(std::move(OR_RETURN_VAL).error())
120#define set_or_return(var, exp) do { if (decltype(auto) OR_RETURN_VAL = (exp); !OR_RETURN_VAL.has_value()) return ::ghassanpl::unexpected(std::move(OR_RETURN_VAL).error()); else var = std::move(OR_RETURN_VAL).value(); } while (0)
121#define let_or_return(var, exp) \
122 decltype(auto) OR_RETURN_VAL = (exp); \
124 return ::ghassanpl::unexpected(std::move(OR_RETURN_VAL).error()); \
125 auto var = std::forward<decltype(OR_RETURN_VAL)>(OR_RETURN_VAL).value()
126#define do_or_return(exp, func) if (decltype(auto) OR_RETURN_VAL = (exp); !OR_RETURN_VAL.has_value()) return ::ghassanpl::unexpected(std::move(OR_RETURN_VAL).error()); else (func)(std::move(OR_RETURN_VAL).value());
127#define or_break(exp) if (decltype(auto) OR_RETURN_VAL = (exp); !OR_RETURN_VAL.has_value()) break
Primary namespace for everything in this library.
auto call_with_expected_ec(FUNC &&func, ARGS &&... args) noexcept(noexcept(func(std::forward< ARGS >(args)...))) -> expected< std::invoke_result_t< FUNC, ARGS &&... >, std::error_code >
Calls the given function with args and an std::error_code as the last argument.