diff options
author | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-05-16 17:38:34 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-16 17:38:34 +0200 |
commit | 77b190d822c1e980b98b84999f0cfb609ed05a49 (patch) | |
tree | 049fc3936343a7af957c0bca20dd1531ae2e5f81 /lib/expected.h | |
parent | 0599ef6e603dce219b2ba000d7322e8d937753b9 (diff) | |
parent | decc676f1e469dc26c80c33da64fad15805de8f2 (diff) | |
download | libquotient-77b190d822c1e980b98b84999f0cfb609ed05a49.tar.gz libquotient-77b190d822c1e980b98b84999f0cfb609ed05a49.zip |
Merge #550: Quotient::Expected and QOlmExpected
Diffstat (limited to 'lib/expected.h')
-rw-r--r-- | lib/expected.h | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/lib/expected.h b/lib/expected.h new file mode 100644 index 00000000..7b9e7f1d --- /dev/null +++ b/lib/expected.h @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: 2022 Kitsune Ral <Kitsune-Ral@users.sf.net> +// SPDX-License-Identifier: LGPL-2.1-or-later + +#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 |