diff --git a/fty/expected.h b/fty/expected.h index 1b3b866..ebd758e 100644 --- a/fty/expected.h +++ b/fty/expected.h @@ -19,6 +19,8 @@ #include #include #include +#include +#include namespace fty { @@ -33,7 +35,7 @@ template class Expected { public: - constexpr Expected() = delete; + constexpr Expected() = default; constexpr Expected(const T& value) noexcept; constexpr Expected(T&& value) noexcept; constexpr Expected(Expected&& other) noexcept; @@ -41,47 +43,48 @@ class Expected constexpr Expected(Unexpected&& unex) noexcept; template constexpr Expected(const Unexpected& unex) noexcept; - ~Expected(); + ~Expected() = default; - Expected(const Expected&) = delete; - Expected& operator=(const Expected&) = delete; + Expected(const Expected& other) = default; + Expected& operator=(const Expected& other) = default; - constexpr const T& value() const& noexcept; - constexpr T& value() & noexcept; - constexpr const T&& value() const&& noexcept; - constexpr T&& value() && noexcept; - constexpr const ErrorT& error() const& noexcept; + constexpr const T& value() const&; + constexpr T& value() &; + constexpr const T&& value() const&&; + constexpr T&& value() &&; + constexpr const ErrorT& error() const&; constexpr bool isValid() const noexcept; explicit constexpr operator bool() const noexcept; - constexpr const T& operator*() const& noexcept; - constexpr T& operator*() & noexcept; - constexpr const T&& operator*() const&& noexcept; - constexpr T&& operator*() && noexcept; + constexpr const T& operator*() const&; + constexpr T& operator*() &; + constexpr const T&& operator*() const&&; + constexpr T&& operator*() &&; constexpr const T* operator->() const noexcept; constexpr T* operator->() noexcept; private: - union { - T m_value; - ErrorT m_error; - }; - bool m_isError = false; + std::variant m_value; }; template class Expected { public: - Expected() noexcept; + Expected() noexcept = default ; template Expected(Unexpected&& unex) noexcept; template Expected(const Unexpected& unex) noexcept; - Expected(const Expected&) = delete; - Expected& operator=(const Expected&) = delete; + Expected(const Expected& other) + { + m_error = std::move(other.error()); + m_isError = other.m_isError; + }; + + Expected& operator=(const Expected&) = default; constexpr bool isValid() const noexcept; constexpr operator bool() const noexcept; @@ -150,137 +153,104 @@ constexpr Expected::Expected(T&& value) noexcept template constexpr Expected::Expected(Expected&& other) noexcept { - if (other.m_isError) { - m_isError = true; - m_error = std::move(other.m_error); - } else { - m_value = std::move(other.m_value); - } + m_value = std::move(other.m_value); } template template constexpr Expected::Expected(Unexpected&& unex) noexcept - : m_error(std::move(unex.message)) - , m_isError(true) + : m_value(std::move(unex.message)) { } template template constexpr Expected::Expected(const Unexpected& unex) noexcept - : m_error(unex.message) - , m_isError(true) -{ -} - -template -Expected::~Expected() + : m_value(unex.message) { - if (m_isError) { - m_error.~ErrorT(); - } else { - m_value.~T(); - } } template -constexpr const T& Expected::value() const& noexcept +constexpr const T& Expected::value() const& { - assert(!m_isError); - return m_value; + return std::get(m_value); } template -constexpr T& Expected::value() & noexcept +constexpr T& Expected::value() & { - assert(!m_isError); - return m_value; + return std::get(m_value); } template -constexpr const T&& Expected::value() const&& noexcept +constexpr const T&& Expected::value() const&& { - assert(!m_isError); - return std::move(m_value); + return std::get(m_value); } template -constexpr T&& Expected::value() && noexcept +constexpr T&& Expected::value() && { - assert(!m_isError); - return std::move(m_value); + return std::get(m_value); } template -constexpr const ErrorT& Expected::error() const& noexcept +constexpr const ErrorT& Expected::error() const& { - assert(m_isError); - return m_error; + assert(std::holds_alternative(m_value)); + return std::get(m_value); } template constexpr bool Expected::isValid() const noexcept { - return !m_isError; + return std::holds_alternative(m_value); } template constexpr Expected::operator bool() const noexcept { - return !m_isError; + return isValid(); } template -constexpr const T& Expected::operator*() const& noexcept +constexpr const T& Expected::operator*() const& { - assert(!m_isError); - return m_value; + return std::get(m_value); } template -constexpr T& Expected::operator*() & noexcept +constexpr T& Expected::operator*() & { - assert(!m_isError); - return m_value; + return std::get(m_value); } template -constexpr const T&& Expected::operator*() const&& noexcept +constexpr const T&& Expected::operator*() const&& { - assert(!m_isError); - return std::move(m_value); + return std::get(m_value); } template -constexpr T&& Expected::operator*() && noexcept +constexpr T&& Expected::operator*() && { - assert(!m_isError); - return std::move(m_value); + return std::get(m_value); } - template constexpr const T* Expected::operator->() const noexcept { - assert(!m_isError); - return &m_value; + return std::get_if(&m_value); } template constexpr T* Expected::operator->() noexcept { - assert(!m_isError); - return &m_value; + return std::get_if(&m_value); } // =========================================================================================================== -template -inline Expected::Expected() noexcept -{ -} - template template inline Expected::Expected(Unexpected&& unex) noexcept @@ -306,7 +276,7 @@ inline constexpr bool Expected::isValid() const noexcept template inline constexpr Expected::operator bool() const noexcept { - return !m_isError; + return isValid(); } template diff --git a/test/expected.cpp b/test/expected.cpp index 4f76391..c557c6a 100644 --- a/test/expected.cpp +++ b/test/expected.cpp @@ -15,12 +15,14 @@ */ #include "fty/expected.h" #include +#include +#include struct St { St() = default; St(const St&) = delete; - St& operator=(const St&) = delete; + St& operator=(const St&) = default; St(St&&) = default; bool func() @@ -29,6 +31,21 @@ struct St } }; +struct Msg +{ + Msg() = default; + Msg(const Msg&) = default; + Msg& operator=(const Msg&) = default; + Msg(Msg&&) = default; + + size_t size() + { + return m_data.size(); + } + + std::map m_data; +}; + TEST_CASE("Expected") { SECTION("Expected") @@ -185,4 +202,50 @@ TEST_CASE("Expected") REQUIRE_THROWS_AS(rethrow_exception(resTriggeredError.error()), std::runtime_error); } + + SECTION("Tests asign operator") + { + fty::Expected result; + fty::Expected result2; + fty::Expected result3; + auto it = fty::Expected(); + CHECK(it); + + auto func = []() -> fty::Expected { + return {}; + }; + auto func2 = []() -> fty::Expected { + return fty::unexpected("some error"); + }; + result = func(); + CHECK(result); + result2 = result; + CHECK(result2); + result3 = func2(); + CHECK(!result3); + CHECK("some error" == result3.error()); + } + + SECTION("Tests asign operator") + { + auto func = []() -> fty::Expected { + Msg msg; + msg.m_data.emplace("keyMsg", "valueMsg"); + return msg; + }; + + auto funcUnexpec = []() -> fty::Expected { + return fty::unexpected("wrong"); + }; + + fty::Expected msg; + msg = func(); + CHECK(msg->size() == 1); + CHECK((*msg).size() == 1); + + fty::Expected unexpec; + unexpec = funcUnexpec(); + CHECK(!unexpec); + CHECK("wrong" == unexpec.error()); + } }