diff --git a/tl/expected.hpp b/tl/expected.hpp index 09370a5..f8d2ec2 100644 --- a/tl/expected.hpp +++ b/tl/expected.hpp @@ -22,6 +22,10 @@ #include #include +#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) +#define TL_EXPECTED_EXCEPTIONS_ENABLED +#endif + #if (defined(_MSC_VER) && _MSC_VER == 1900) /// \exclude #define TL_EXPECTED_MSVC2015 @@ -186,7 +190,7 @@ static constexpr unexpect_t unexpect{}; namespace detail { template [[noreturn]] constexpr void throw_exception(E &&e) { -#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED throw std::forward(e); #else #ifdef _MSC_VER @@ -196,7 +200,7 @@ template #endif #endif } - + #ifndef TL_TRAITS_MUTEX #define TL_TRAITS_MUTEX // C++14-style aliases for brevity @@ -383,7 +387,7 @@ template struct expected_storage_base { ~expected_storage_base() = default; union { - char m_no_init; + char m_no_init; T m_val; unexpected m_unexpect; }; @@ -429,7 +433,7 @@ template struct expected_storage_base { } union { - char m_no_init; + char m_no_init; T m_val; unexpected m_unexpect; }; @@ -473,7 +477,7 @@ template struct expected_storage_base { } } union { - char m_no_init; + char m_no_init; T m_val; unexpected m_unexpect; }; @@ -539,7 +543,7 @@ template struct expected_storage_base { struct dummy {}; union { - char m_no_init; + char m_no_init; dummy m_val; unexpected m_unexpect; }; @@ -568,6 +572,8 @@ struct expected_operations_base : expected_storage_base { this->m_has_val = false; } + #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + // These assign overloads ensure that the most efficient assignment // implementation is used while maintaining the strong exception guarantee. // The problematic case is where rhs has a value, but *this does not. @@ -658,6 +664,29 @@ struct expected_operations_base : expected_storage_base { } } + #else + + // If exceptions are disabled then we can just copy-construct + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(rhs.get()); + } else { + assign_common(rhs); + } + } + + void assign(expected_operations_base &&rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(std::move(rhs).get()); + } else { + assign_common(rhs); + } + } + + #endif + // The common part of move/copy assigning template void assign_common(Rhs &&rhs) { if (this->m_has_val) { @@ -1559,6 +1588,8 @@ public: } else { auto tmp = std::move(err()); err().~unexpected(); + + #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED try { ::new (valptr()) T(std::move(v)); this->m_has_val = true; @@ -1566,6 +1597,10 @@ public: err() = std::move(tmp); throw; } + #else + ::new (valptr()) T(std::move(v)); + this->m_has_val = true; + #endif } return *this; @@ -1623,6 +1658,7 @@ public: auto tmp = std::move(err()); err().~unexpected(); + #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED try { ::new (valptr()) T(std::forward(args)...); this->m_has_val = true; @@ -1630,6 +1666,10 @@ public: err() = std::move(tmp); throw; } + #else + ::new (valptr()) T(std::forward(args)...); + this->m_has_val = true; + #endif } } @@ -1659,6 +1699,7 @@ public: auto tmp = std::move(err()); err().~unexpected(); + #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED try { ::new (valptr()) T(il, std::forward(args)...); this->m_has_val = true; @@ -1666,6 +1707,10 @@ public: err() = std::move(tmp); throw; } + #else + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; + #endif } }