diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/expected.h | 74 |
2 files changed, 75 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 537d580e..404ba87c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,6 +118,7 @@ list(APPEND lib_SRCS lib/quotient_export.h lib/function_traits.h lib/function_traits.cpp lib/omittable.h + lib/expected.h lib/networkaccessmanager.h lib/networkaccessmanager.cpp lib/connectiondata.h lib/connectiondata.cpp lib/connection.h lib/connection.cpp 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 |