From 4f8e1060a308015d343b51de6b00e2102934f69a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 7 Dec 2018 18:54:55 +0100 Subject: core: implement 'unexpect' --- CMakeLists.txt | 1 + src/expected.hpp | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 src/expected.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6326c05..86de9c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ set(WANDA_CORE_HEADERS "src/control_connection.hpp" "src/deferred_failure.hpp" "src/environment.hpp" + "src/expected.hpp" "src/keyed.hpp" "src/message.hpp" "src/optional.hpp" diff --git a/src/expected.hpp b/src/expected.hpp new file mode 100644 index 0000000..8cacefe --- /dev/null +++ b/src/expected.hpp @@ -0,0 +1,227 @@ +#ifndef WANDA_EXPECTED_HPP +#define WANDA_EXPECTED_HPP + +#include +#include +#include + +namespace wanda +{ + +template +struct unexpected +{ + static_assert(!std::is_same_v, "ErrorType can not be 'void'!"); + static_assert(!std::is_array_v, "ErrorType can not be an array type!"); + + /** + * @brief Copy construct a new @p unexpected from another @p unexpected + */ + constexpr unexpected(unexpected const &) = default; + + /** + * @brief Move construct a new @p unexpected from another @p unexpected + */ + constexpr unexpected(unexpected &&) = default; + + /** + * @brief Construct a new @p unexpected by direct initializing the error object from @p args + */ + template + constexpr explicit unexpected(std::in_place_t, Args &&... args) : m_error(std::forward(args)...) {} + + /** + * @brief Construct a new @p unexpected by direct initializing the error object from @p il and @p args + */ + template < + typename U, + typename... Args, + std::enable_if_t, Args...>> * = nullptr> + constexpr explicit unexpected(std::in_place_t, std::initializer_list il, Args &&... args) : m_error(il, std::forward(args)...) {} + + /** + * @brief Construct a new @p unexpected by direct initializing the error object from @p error + */ + template < + typename Err = ErrorType, + std::enable_if_t && + !std::is_same_v>, std::in_place_t> && + !std::is_same_v>, unexpected>> * = nullptr> + constexpr explicit unexpected(Err &&error) : m_error(std::forward(error)) {} + + /** + * @brief Construct a new @p unexpected by copying the value of another @p unexpected of different error type + */ + template < + typename Err, + std::enable_if_t && + !std::is_constructible_v &> && + !std::is_constructible_v> && + !std::is_constructible_v const &> && + !std::is_constructible_v const> && + !std::is_convertible_v &, ErrorType> && + !std::is_convertible_v, ErrorType> && + !std::is_convertible_v const &, ErrorType> && + !std::is_convertible_v const, ErrorType>)> * = nullptr, + std::enable_if_t> * = nullptr> + constexpr explicit unexpected(unexpected const &error) : m_error(error.m_error) {} + + /** + * @brief Construct a new @p unexpected by copying the value of another @p unexpected of different error type + */ + template < + typename Err, + std::enable_if_t && + !std::is_constructible_v &> && + !std::is_constructible_v> && + !std::is_constructible_v const &> && + !std::is_constructible_v const> && + !std::is_convertible_v &, ErrorType> && + !std::is_convertible_v, ErrorType> && + !std::is_convertible_v const &, ErrorType> && + !std::is_convertible_v const, ErrorType>)> * = nullptr, + std::enable_if_t> * = nullptr> + constexpr unexpected(unexpected const &error) : m_error(error.m_error) {} + + /** + * @brief Construct a new @p unexpected by moving the value of another @p unexpected of different error type + */ + template < + typename Err, + std::enable_if_t && + !std::is_constructible_v &> && + !std::is_constructible_v> && + !std::is_constructible_v const &> && + !std::is_constructible_v const> && + !std::is_convertible_v &, ErrorType> && + !std::is_convertible_v, ErrorType> && + !std::is_convertible_v const &, ErrorType> && + !std::is_convertible_v const, ErrorType>)> * = nullptr, + std::enable_if_t> * = nullptr> + constexpr explicit unexpected(unexpected &&error) : m_error(std::move(error.m_error)) {} + + /** + * @brief Construct a new @p unexpected by moving the value of another @p unexpected of different error type + */ + template < + typename Err, + std::enable_if_t && + !std::is_constructible_v &> && + !std::is_constructible_v> && + !std::is_constructible_v const &> && + !std::is_constructible_v const> && + !std::is_convertible_v &, ErrorType> && + !std::is_convertible_v, ErrorType> && + !std::is_convertible_v const &, ErrorType> && + !std::is_convertible_v const, ErrorType>)> * = nullptr, + std::enable_if_t> * = nullptr> + constexpr unexpected(unexpected &&error) : m_error(std::move(error.m_error)) {} + + /** + * @brief Get the error value contained in this @p unexpected instance + */ + constexpr ErrorType const &value() const & + { + return m_error; + } + + /** + * @brief Get the error value contained in this @p unexpected instance + */ + constexpr ErrorType &value() & + { + return m_error; + } + + /** + * @brief Get the error value contained in this @p unexpected instance + */ + constexpr ErrorType &&value() && + { + return std::move(m_error); + } + + /** + * @brief Get the error value contained in this @p unexpected instance + */ + constexpr ErrorType const &&value() const && + { + return std::move(m_error); + } + + /** + * @brief Swap the error value of this @p unexpected instance with the one of @p other + */ + void swap(unexpected &other) noexcept(std::is_nothrow_swappable_v) + { + using std::swap; + swap(m_error, other.m_error); + } + + template + friend constexpr bool operator==(unexpected const &lhs, unexpected const &rhs); + + template + friend constexpr bool operator!=(unexpected const &lhs, unexpected const &rhs); + + template < + typename Err, + std::enable_if_t> *> + friend void swap(unexpected &lhs, unexpected &rhs); + + private: + ErrorType m_error; +}; + +template +unexpected(ErrorType)->unexpected; + +/** + * @brief Compare two @p unexpected instances for equality + */ +template +constexpr bool operator==(unexpected const &lhs, unexpected const &rhs) +{ + return lhs.m_error == rhs.m_error; +} + +/** + * @brief Compare two @p unexpected instances for inequality + */ +template +constexpr bool operator!=(unexpected const &lhs, unexpected const &rhs) +{ + return lhs.m_error != rhs.m_error; +} + +/** + * @brief Swap the error values of two @p unexpected instances + */ +template < + typename Err, + std::enable_if_t> * = nullptr> +void swap(unexpected &lhs, unexpected &rhs) +{ + lhs.swap(rhs); +} + +/** + * @brief A tag type for @p unexpected + */ +struct unexpect_t +{ + explicit unexpect_t() = default; +}; + +/** + * @brief A tap for @p unexpected + */ +inline constexpr unexpect_t unexpect{}; + +} // namespace wanda + +#endif \ No newline at end of file -- cgit v1.2.3