diff options
author | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-05-16 10:41:36 +0200 |
---|---|---|
committer | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-05-16 10:42:10 +0200 |
commit | 9c8c33ab0b2138b45cbfe29f4be235f631730826 (patch) | |
tree | e14881ea59b50e42445a502589fb1b9cf5c8d46e /lib | |
parent | 3fcc0c5acb160364e819688cc67a8aaf814fafef (diff) | |
download | libquotient-9c8c33ab0b2138b45cbfe29f4be235f631730826.tar.gz libquotient-9c8c33ab0b2138b45cbfe29f4be235f631730826.zip |
Expected<>
This is a minimal implementation along the lines of `std::expected<>`
introduced in C++23; once compilers catch up with C++23 support, it may
become simply a typedef of std::expected. There are no tests as yet; but
the following commits will introduce QOlmExpected that would replace
the current `std::variant<T, QOlmError>` pattern used throughout `QOlm*`
classes, automatically pulling Expected under the coverage of `QOlm*`
unit tests.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/expected.h | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/lib/expected.h b/lib/expected.h new file mode 100644 index 00000000..c8b8fd64 --- /dev/null +++ b/lib/expected.h @@ -0,0 +1,74 @@ +#pragma once + +#include <variant> + +namespace Quotient { + +//! \brief A minimal subset of std::expected from C++23 +template <typename T, typename E, + std::enable_if_t<!std::is_same_v<T, E>, bool> = true> +class Expected { +private: + template <typename X> + using enable_if_constructible_t = std::enable_if_t< + std::is_constructible_v<T, X> || std::is_constructible_v<E, X>>; + +public: + using value_type = T; + using error_type = E; + + Expected() = default; + explicit Expected(const Expected&) = default; + explicit Expected(Expected&&) noexcept = default; + + template <typename X, typename = enable_if_constructible_t<X>> + Expected(X&& x) + : data(std::forward<X>(x)) + {} + + Expected& operator=(const Expected&) = default; + Expected& operator=(Expected&&) noexcept = default; + + template <typename X, typename = enable_if_constructible_t<X>> + Expected& operator=(X&& x) + { + data = std::forward<X>(x); + return *this; + } + + bool has_value() const { return std::holds_alternative<T>(data); } + explicit operator bool() const { return has_value(); } + + const value_type& value() const& { return std::get<T>(data); } + value_type& value() & { return std::get<T>(data); } + value_type value() && { return std::get<T>(std::move(data)); } + + const value_type& operator*() const& { return value(); } + value_type& operator*() & { return value(); } + + const value_type* operator->() const& { return std::get_if<T>(&data); } + value_type* operator->() & { return std::get_if<T>(&data); } + + template <class U> + T value_or(U&& fallback) const& + { + if (has_value()) + return value(); + return std::forward<U>(fallback); + } + template <class U> + T value_or(U&& fallback) && + { + if (has_value()) + return value(); + return std::forward<U>(fallback); + } + + const E& error() const& { return std::get<E>(data); } + E& error() & { return std::get<E>(data); } + +private: + std::variant<T, E> data; +}; + +} // namespace Quotient |