header_utils
Loading...
Searching...
No Matches
expected.h
1
4
5#pragma once
6
7#include <system_error>
8#include <optional>
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
12#include <expected>
13namespace ghassanpl
14{
15 using std::expected;
16 using std::unexpected;
17}
18#elif __has_include(<tl/expected.hpp>)
19#include <tl/expected.hpp>
20namespace ghassanpl
21{
22 using tl::expected;
23 using tl::unexpected;
24}
25#elif defined(GHPL_EXPECTED_HEADER)
26#include GHPL_EXPECTED_HEADER
27#else
28#error "No expected implementation found"
29#endif
30
31namespace ghassanpl
32{
33 namespace detail
34 {
35 template <typename T>
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; }
39
40 template <typename T>
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>{}; }
44
45 template <typename T>
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>);
48 }
49
50 template <typename T>
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>>);
56
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>
62 {
63 std::error_code ec{};
64 if constexpr (std::is_void_v<std::invoke_result_t<FUNC, ARGS&&...>>)
65 {
66 func(std::forward<ARGS>(args)..., ec);
67 if (ec)
68 return unexpected(ec);
69 return {};
70 }
71 else
72 {
73 auto result = func(std::forward<ARGS>(args)..., ec);
74 if (ec)
75 return unexpected(ec);
76 return result;
77 }
78 }
79
80 template <typename T>
81 struct undroppable final
82 {
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)...)
86 {
87 }
88
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;
93
94 T handle() noexcept
95 {
96 return std::exchange(m_value, {}).value();
97 }
98
99 bool was_handled() const noexcept { return !m_value.has_value(); }
100
101 T const& value() const noexcept { return m_value.value(); }
102 T& value() noexcept { return m_value.value(); }
103
104 ~undroppable() noexcept(false)
105 {
106 if (m_value)
107 throw std::move(m_value.value());
108 }
109
110 private:
111
112 std::optional<T> m_value;
113 };
114
115
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); \
123 if (!OR_RETURN_VAL)\
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
128}
Primary namespace for everything in this library.
Definition align+rec2.h:10
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.
Definition expected.h:60