From 664bdac4bddd105925f8cc7d4b910af4c72d1151 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 21 Jan 2024 15:02:01 +0000 Subject: [PATCH 1/5] Initial refactor --- include/etl/optional.h | 437 +---------------------------------------- 1 file changed, 1 insertion(+), 436 deletions(-) diff --git a/include/etl/optional.h b/include/etl/optional.h index d85763d2..c638427c 100644 --- a/include/etl/optional.h +++ b/include/etl/optional.h @@ -103,15 +103,8 @@ namespace etl /// See http://en.cppreference.com/w/cpp/utility/optional ///\tparam T The type to store. ///\ingroup utilities - //***************************************************************************** - template ::value> - class optional; - - //***************************************************************************** - /// For non POD types. - //***************************************************************************** template - class optional + class optional { public: @@ -682,434 +675,6 @@ namespace etl storage_type storage; }; - //***************************************************************************** - /// For arithmetic or pointer types. - ///\tparam T The type to store. - ///\ingroup utilities - //***************************************************************************** - template - class optional - { - public: - - typedef T value_type; - - //*************************************************************************** - /// Constructor. - //*************************************************************************** - ETL_CONSTEXPR14 optional() - : valid(false) - , storage() - { - } - - //*************************************************************************** - /// Constructor with nullopt. - //*************************************************************************** - ETL_CONSTEXPR14 optional(etl::nullopt_t) - : valid(false) - , storage() - { - } - - //*************************************************************************** - /// Copy constructor. - //*************************************************************************** - ETL_CONSTEXPR14 optional(const optional& other) - : valid(bool(other)) - , storage(other.storage) - { - } - -#if ETL_USING_CPP11 - //*************************************************************************** - /// Move constructor. - //*************************************************************************** - ETL_CONSTEXPR14 optional(optional&& other) - : valid(bool(other)) - , storage(etl::move(other.storage)) - { - } -#endif - - //*************************************************************************** - /// Constructor from value type. - //*************************************************************************** - ETL_CONSTEXPR14 optional(const T& value_) - : valid(true) - , storage(value_) - { - } - -#if ETL_USING_CPP11 - //*************************************************************************** - /// Constructor from value type. - //*************************************************************************** - ETL_CONSTEXPR14 optional(T&& value_) - : valid(true) - , storage(etl::move(value_)) - { - } -#endif - - //*************************************************************************** - /// Assignment operator from nullopt. - //*************************************************************************** - ETL_CONSTEXPR14 optional& operator =(etl::nullopt_t) - { - valid = false; - return *this; - } - - //*************************************************************************** - /// Assignment operator from optional. - //*************************************************************************** - ETL_CONSTEXPR14 optional& operator =(const optional& other) - { - if (this != &other) - { - storage.value = other.storage.value; - valid = other.valid; - } - - return *this; - } - -#if ETL_USING_CPP11 - //*************************************************************************** - /// Assignment operator from optional. - //*************************************************************************** - ETL_CONSTEXPR14 optional& operator =(optional&& other) - { - if (this != &other) - { - storage.value = etl::move(other.storage.value); - valid = other.valid; - } - - return *this; - } -#endif - - //*************************************************************************** - /// Assignment operator from value type. - //*************************************************************************** - ETL_CONSTEXPR14 optional& operator =(const T& value_) - { - storage.value = value_; - valid = true; - - return *this; - } - -#if ETL_USING_CPP11 - //*************************************************************************** - /// Assignment operator from value type. - //*************************************************************************** - ETL_CONSTEXPR14 optional& operator =(T&& value_) - { - storage.value = etl::move(value_); - valid = true; - - return *this; - } -#endif - - //*************************************************************************** - /// Pointer operator. - //*************************************************************************** - ETL_CONSTEXPR14 T* operator ->() - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); -#endif - - return &storage.value; - } - - //*************************************************************************** - /// Pointer operator. - //*************************************************************************** - ETL_CONSTEXPR14 const T* operator ->() const - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); -#endif - - return &storage.value; - } - - //*************************************************************************** - /// Dereference operator. - //*************************************************************************** - ETL_CONSTEXPR14 T& operator *() ETL_LVALUE_REF_QUALIFIER - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); -#endif - - return storage.value; - } - - //*************************************************************************** - /// Dereference operator. - //*************************************************************************** - ETL_CONSTEXPR14 const T& operator *() const ETL_LVALUE_REF_QUALIFIER - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); -#endif - - return storage.value; - } - -#if ETL_USING_CPP11 - //*************************************************************************** - /// Dereference operator. - //*************************************************************************** - ETL_CONSTEXPR14 T&& operator *()&& - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); -#endif - - return etl::move(storage.value); - } - - //*************************************************************************** - /// Dereference operator. - //*************************************************************************** - ETL_CONSTEXPR14 const T&& operator *() const&& - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); -#endif - - return etl::move(storage.value); - } -#endif - - //*************************************************************************** - /// Bool conversion operator. - //*************************************************************************** - ETL_CONSTEXPR14 - ETL_EXPLICIT operator bool() const - { - return valid; - } - - //*************************************************************************** - // Check whether optional contains value - //*************************************************************************** - ETL_CONSTEXPR14 bool has_value() const ETL_NOEXCEPT - { - return valid; - } - - //*************************************************************************** - /// Get a reference to the value. - //*************************************************************************** - ETL_CONSTEXPR14 T& value() ETL_LVALUE_REF_QUALIFIER - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); -#endif - - return storage.value; - } - - //*************************************************************************** - /// Get a const reference to the value. - //*************************************************************************** - ETL_CONSTEXPR14 const T& value() const ETL_LVALUE_REF_QUALIFIER - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); -#endif - - return storage.value; - } - - //*************************************************************************** - /// Gets the value or a default if no valid. - //*************************************************************************** - ETL_CONSTEXPR14 T value_or(const T& default_value) const ETL_LVALUE_REF_QUALIFIER - { - return valid ? value() : default_value; - } - -#if ETL_USING_CPP11 - //*************************************************************************** - /// Get an rvalue reference to the value. - //*************************************************************************** - ETL_CONSTEXPR14 T&& value()&& - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); -#endif - - return etl::move(storage.value); - } - - //*************************************************************************** - /// Get a const rvalue reference to the value. - //*************************************************************************** - ETL_CONSTEXPR14 const T&& value() const&& - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); -#endif - - return etl::move(storage.value); - } - - //*************************************************************************** - /// Gets the value or a default if not valid. - //*************************************************************************** - template - ETL_CONSTEXPR20_STL - etl::enable_if_t::value, T> - value_or(U&& default_value) const& - { - if (has_value()) - { - return value(); - } - else - { - return static_cast(etl::forward(default_value)); - } - } - - //*************************************************************************** - /// Gets the value or a default if not valid. - //*************************************************************************** - template - ETL_CONSTEXPR20_STL - etl::enable_if_t::value, T> - value_or(U&& default_value) && - { - if (has_value()) - { - return etl::move(value()); - } - else - { - return static_cast(etl::forward(default_value)); - } - } -#endif - - //*************************************************************************** - /// Swaps this value with another. - //*************************************************************************** - ETL_CONSTEXPR14 void swap(optional& other) - { - optional temp(*this); - *this = other; - other = temp; - } - - //*************************************************************************** - /// Reset back to invalid. - //*************************************************************************** - ETL_CONSTEXPR14 void reset() - { - valid = false; - } - -#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_OPTIONAL_FORCE_CPP03_IMPLEMENTATION) - //************************************************************************* - /// Emplaces a value. - ///\param args The arguments to construct with. - //************************************************************************* - template - ETL_CONSTEXPR14 void emplace(Args && ... args) - { - storage.value = T(ETL_OR_STD::forward(args)...); - valid = true; - } -#else - //************************************************************************* - /// Emplaces a value. - /// 0 parameters. - //************************************************************************* - void emplace() - { - storage.value = value_type(); - valid = true; - } - - //************************************************************************* - /// Emplaces a value. - /// 1 parameter. - //************************************************************************* - template - void emplace(const T1& value1) - { - storage.value = value1; - valid = true; - } - - //************************************************************************* - /// Emplaces a value. - /// 2 parameters. - //************************************************************************* - template - void emplace(const T1& value1, const T2& value2) - { - storage.value = T(value1, value2); - valid = true; - } - - //************************************************************************* - /// Emplaces a value. - /// 3 parameters. - //************************************************************************* - template - void emplace(const T1& value1, const T2& value2, const T3& value3) - { - storage.value = T(value1, value2, value3); - valid = true; - } - - //************************************************************************* - /// Emplaces a value. - /// 4 parameters. - //************************************************************************* - template - void emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) - { - storage.value = T(value1, value2, value3, value4); - valid = true; - } -#endif - - private: - - bool valid; - - struct dummy_t {}; - - union storage_type - { - dummy_t dummy; - T value; - - ETL_CONSTEXPR storage_type() - : dummy() - { - } - - ETL_CONSTEXPR storage_type(const T& v) - : value(v) - { - } - }; - - storage_type storage; - }; - #include "private/diagnostic_uninitialized_push.h" //*************************************************************************** From 1a0036366ddd43a13c8fd71af51e10c89b70241c Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 21 Jan 2024 15:41:50 +0000 Subject: [PATCH 2/5] Added test for #819 --- test/test_optional.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test_optional.cpp b/test/test_optional.cpp index 8f07862b..a6bbc650 100644 --- a/test/test_optional.cpp +++ b/test/test_optional.cpp @@ -629,6 +629,21 @@ namespace CHECK_EQUAL(42, (*opt).v); } #endif + + //************************************************************************* + TEST(test_optional_issue_819) + { + // The code below should compile without error. + class optional_type + { + public: + + static etl::optional function() + { + return {}; + } + }; + } }; } From 2619b9e307b56f245d75d9ab771da6bf53f43178 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 2 Feb 2024 12:42:07 +0000 Subject: [PATCH 3/5] Refactored etl::optional implementation --- include/etl/optional.h | 186 +++++++++++++++++++++++++++++------------ 1 file changed, 134 insertions(+), 52 deletions(-) diff --git a/include/etl/optional.h b/include/etl/optional.h index c638427c..69c136f4 100644 --- a/include/etl/optional.h +++ b/include/etl/optional.h @@ -103,6 +103,7 @@ namespace etl /// See http://en.cppreference.com/w/cpp/utility/optional ///\tparam T The type to store. ///\ingroup utilities + //***************************************************************************** template class optional { @@ -113,7 +114,7 @@ namespace etl //*************************************************************************** /// Constructor. //*************************************************************************** - ETL_CONSTEXPR + ETL_CONSTEXPR20_STL optional() : storage() { @@ -122,7 +123,7 @@ namespace etl //*************************************************************************** /// Constructor with nullopt. //*************************************************************************** - ETL_CONSTEXPR + ETL_CONSTEXPR20_STL optional(etl::nullopt_t) : storage() { @@ -581,7 +582,14 @@ namespace etl struct dummy_t {}; - struct storage_type + template ::value> + struct storage_type; + + //************************************* + // Non-POD + //************************************* + template + struct storage_type { //******************************* ETL_CONSTEXPR20_STL @@ -600,33 +608,29 @@ namespace etl //******************************* ETL_CONSTEXPR20_STL - void construct(const T& value_) + void construct(const TValue& value_) { if (valid) { - u.value = value_; - } - else - { - etl::construct_at(&u.value, value_); - valid = true; + etl::destroy_at(&u.value); } + + etl::construct_at(&u.value, value_); + valid = true; } #if ETL_USING_CPP11 //******************************* ETL_CONSTEXPR20_STL - void construct(T&& value_) + void construct(TValue&& value_) { if (valid) { - u.value = etl::move(value_); - } - else - { - etl::construct_at(&u.value, etl::move(value_)); - valid = true; + etl::destroy_at(&u.value); } + + etl::construct_at(&u.value, etl::move(value_)); + valid = true; } //******************************* @@ -634,7 +638,11 @@ namespace etl ETL_CONSTEXPR20_STL void construct(TArgs&&... args) { - destroy(); + if (valid) + { + etl::destroy_at(&u.value); + } + etl::construct_at(&u.value, etl::forward(args)...); valid = true; } @@ -666,13 +674,87 @@ namespace etl } dummy_t dummy; - T value; + TValue value; } u; bool valid; }; - storage_type storage; + //************************************* + // POD + //************************************* + template + struct storage_type + { + //******************************* + ETL_CONSTEXPR20_STL + storage_type() + : valid(false) + { + } + + //******************************* + ETL_CONSTEXPR20_STL + ~storage_type() + { + } + + //******************************* + ETL_CONSTEXPR20_STL + void construct(const TValue& value_) + { + u.value = value_; + valid = true; + } + +#if ETL_USING_CPP11 + //******************************* + ETL_CONSTEXPR20_STL + void construct(TValue&& value_) + { + u.value = value_; + valid = true; + } + + //******************************* + template + ETL_CONSTEXPR20_STL + void construct(TArgs&&... args) + { + u.value = TValue(etl::forward(args)...); + valid = true; + } +#endif + + //******************************* + ETL_CONSTEXPR20_STL + void destroy() + { + valid = false; + } + + //******************************* + union union_type + { + ETL_CONSTEXPR20_STL + union_type() + : dummy() + { + } + + ETL_CONSTEXPR20_STL + ~union_type() + { + } + + dummy_t dummy; + TValue value; + } u; + + bool valid; + }; + + storage_type storage; }; #include "private/diagnostic_uninitialized_push.h" @@ -681,7 +763,7 @@ namespace etl /// Equality operator. cppreference 1 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator ==(const etl::optional& lhs, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator ==(const etl::optional& lhs, const etl::optional& rhs) { if (lhs.has_value() != rhs.has_value()) { @@ -701,7 +783,7 @@ namespace etl /// Equality operator. cppreference 2 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator !=(const etl::optional& lhs, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator !=(const etl::optional& lhs, const etl::optional& rhs) { return !(lhs == rhs); } @@ -710,7 +792,7 @@ namespace etl /// Less than operator. cppreference 3 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator <(const etl::optional& lhs, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator <(const etl::optional& lhs, const etl::optional& rhs) { if (!rhs.has_value()) { @@ -730,7 +812,7 @@ namespace etl /// Less than equal operator. cppreference 4 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator <=(const etl::optional& lhs, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator <=(const etl::optional& lhs, const etl::optional& rhs) { return !(rhs < lhs); } @@ -739,7 +821,7 @@ namespace etl /// greater than operator. cppreference 5 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator >(const etl::optional& lhs, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator >(const etl::optional& lhs, const etl::optional& rhs) { return (rhs < lhs); } @@ -748,7 +830,7 @@ namespace etl /// greater than equal operator. cppreference 6 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator >=(const etl::optional& lhs, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator >=(const etl::optional& lhs, const etl::optional& rhs) { return !(lhs < rhs); } @@ -757,7 +839,7 @@ namespace etl /// Equality operator. cppreference 7 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator ==(const etl::optional& lhs, etl::nullopt_t) + ETL_CONSTEXPR20_STL bool operator ==(const etl::optional& lhs, etl::nullopt_t) { return !lhs.has_value(); } @@ -766,7 +848,7 @@ namespace etl /// Equality operator. cppreference 8 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator ==(etl::nullopt_t, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator ==(etl::nullopt_t, const etl::optional& rhs) { return !rhs.has_value(); } @@ -775,7 +857,7 @@ namespace etl /// Inequality operator. cppreference 9 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator !=(const etl::optional& lhs, etl::nullopt_t) + ETL_CONSTEXPR20_STL bool operator !=(const etl::optional& lhs, etl::nullopt_t) { return !(lhs == etl::nullopt); } @@ -784,7 +866,7 @@ namespace etl /// Inequality operator. cppreference 10 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator !=(etl::nullopt_t , const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator !=(etl::nullopt_t , const etl::optional& rhs) { return !(etl::nullopt == rhs); } @@ -793,7 +875,7 @@ namespace etl /// Less than operator. cppreference 11 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator <(const etl::optional&, etl::nullopt_t) + ETL_CONSTEXPR20_STL bool operator <(const etl::optional&, etl::nullopt_t) { return false; } @@ -802,7 +884,7 @@ namespace etl /// Less than operator. cppreference 12 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator <(etl::nullopt_t, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator <(etl::nullopt_t, const etl::optional& rhs) { return rhs.has_value(); } @@ -811,7 +893,7 @@ namespace etl /// Less than equal operator. cppreference 13 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator <=(const etl::optional& lhs, etl::nullopt_t) + ETL_CONSTEXPR20_STL bool operator <=(const etl::optional& lhs, etl::nullopt_t) { return !lhs.has_value(); } @@ -820,7 +902,7 @@ namespace etl /// Less than equal operator. cppreference 14 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator <=(etl::nullopt_t, const etl::optional&) + ETL_CONSTEXPR20_STL bool operator <=(etl::nullopt_t, const etl::optional&) { return true; } @@ -829,7 +911,7 @@ namespace etl /// Greater than operator. cppreference 15 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator >(const etl::optional& lhs, etl::nullopt_t) + ETL_CONSTEXPR20_STL bool operator >(const etl::optional& lhs, etl::nullopt_t) { return lhs.has_value(); } @@ -838,7 +920,7 @@ namespace etl /// Greater than operator. cppreference 16 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator >(etl::nullopt_t, const etl::optional&) + ETL_CONSTEXPR20_STL bool operator >(etl::nullopt_t, const etl::optional&) { return false; } @@ -847,7 +929,7 @@ namespace etl /// Greater than equal operator. cppreference 17 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator >=(const etl::optional&, etl::nullopt_t) + ETL_CONSTEXPR20_STL bool operator >=(const etl::optional&, etl::nullopt_t) { return true; } @@ -856,7 +938,7 @@ namespace etl /// Greater than equal operator. cppreference 18 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator >=(etl::nullopt_t, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator >=(etl::nullopt_t, const etl::optional& rhs) { return !rhs.has_value(); } @@ -865,7 +947,7 @@ namespace etl /// Equality operator. cppreference 19 //************************************************************************** template - ETL_CONSTEXPR14 bool operator ==(const etl::optional& lhs, const U& rhs) + ETL_CONSTEXPR20_STL bool operator ==(const etl::optional& lhs, const U& rhs) { return lhs.has_value() ? lhs.value() == rhs : false; } @@ -874,7 +956,7 @@ namespace etl /// Inequality operator. cppreference 21 //************************************************************************** template - ETL_CONSTEXPR14 bool operator !=(const etl::optional& lhs, const U& rhs) + ETL_CONSTEXPR20_STL bool operator !=(const etl::optional& lhs, const U& rhs) { return !(lhs == rhs); } @@ -883,7 +965,7 @@ namespace etl /// Equality operator. cppreference 20 //************************************************************************** template - ETL_CONSTEXPR14 bool operator ==(const U& lhs, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator ==(const U& lhs, const etl::optional& rhs) { return rhs.has_value() ? rhs.value() == lhs : false; } @@ -892,7 +974,7 @@ namespace etl /// Inequality operator. cppreference 22 //************************************************************************** template - ETL_CONSTEXPR14 bool operator !=(const U& lhs, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator !=(const U& lhs, const etl::optional& rhs) { return !(lhs == rhs); } @@ -901,7 +983,7 @@ namespace etl /// Less than operator. cppreference 23 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator <(const etl::optional& lhs, const U& rhs) + ETL_CONSTEXPR20_STL bool operator <(const etl::optional& lhs, const U& rhs) { return lhs.has_value() ? lhs.value() < rhs : true; } @@ -910,7 +992,7 @@ namespace etl /// Less than operator. cppreference 24 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator <(const U& lhs, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator <(const U& lhs, const etl::optional& rhs) { return rhs.has_value() ? lhs < rhs.value() : false; } @@ -919,7 +1001,7 @@ namespace etl /// Less than equal operator. cppreference 25 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator <=(const etl::optional& lhs, const U& rhs) + ETL_CONSTEXPR20_STL bool operator <=(const etl::optional& lhs, const U& rhs) { return lhs.has_value() ? lhs.value() <= rhs : true; } @@ -928,7 +1010,7 @@ namespace etl /// Less than equal operator. cppreference 26 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator <=(const U& lhs, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator <=(const U& lhs, const etl::optional& rhs) { return rhs.has_value() ? lhs <= rhs.value() : false; } @@ -937,7 +1019,7 @@ namespace etl /// Greater than operator. cppreference 27 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator >(const etl::optional& lhs, const U& rhs) + ETL_CONSTEXPR20_STL bool operator >(const etl::optional& lhs, const U& rhs) { return lhs.has_value() ? lhs.value() > rhs : false; } @@ -946,7 +1028,7 @@ namespace etl /// Greater than operator. cppreference 28 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator >(const U& lhs, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator >(const U& lhs, const etl::optional& rhs) { return rhs.has_value() ? lhs > rhs.value() : true; } @@ -955,7 +1037,7 @@ namespace etl /// Greater than equal operator. cppreference 29 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator >=(const etl::optional& lhs, const U& rhs) + ETL_CONSTEXPR20_STL bool operator >=(const etl::optional& lhs, const U& rhs) { return lhs.has_value() ? lhs.value() >= rhs : false; } @@ -964,7 +1046,7 @@ namespace etl /// Greater than equal operator. cppreference 30 //*************************************************************************** template - ETL_CONSTEXPR14 bool operator >=(const U& lhs, const etl::optional& rhs) + ETL_CONSTEXPR20_STL bool operator >=(const U& lhs, const etl::optional& rhs) { return rhs.has_value() ? lhs >= rhs.value() : true; } @@ -975,7 +1057,7 @@ namespace etl /// Make an optional. //*************************************************************************** template - ETL_CONSTEXPR14 etl::optional::type> make_optional(T& value) + ETL_CONSTEXPR20_STL etl::optional::type> make_optional(T& value) { return etl::optional::type>(value); } @@ -993,7 +1075,7 @@ namespace etl /// Swaps the values. //************************************************************************* template -ETL_CONSTEXPR14 void swap(etl::optional& lhs, etl::optional& rhs) +ETL_CONSTEXPR20_STL void swap(etl::optional& lhs, etl::optional& rhs) { lhs.swap(rhs); } From 3cbc73e0c904c394b56f89e6c4fb8148346426b6 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 9 Feb 2024 11:04:39 +0000 Subject: [PATCH 4/5] Updated unit tests for constexpr optional --- include/etl/optional.h | 2237 ++++++++++++++++++++++++++++++---------- test/test_optional.cpp | 251 ++++- 2 files changed, 1923 insertions(+), 565 deletions(-) diff --git a/include/etl/optional.h b/include/etl/optional.h index 69c136f4..7b55695f 100644 --- a/include/etl/optional.h +++ b/include/etl/optional.h @@ -97,6 +97,1134 @@ namespace etl } }; + //***************************************************************************** + // Implementations for trivial and non trivial types. + //***************************************************************************** + namespace private_optional + { + template ::value> + class optional_impl; + + //***************************************************************************** + // Implementation for non trivial types. + //***************************************************************************** + template + class optional_impl + { + protected: + + typedef T value_type; + + //*************************************************************************** + /// Constructor. + //*************************************************************************** + ETL_CONSTEXPR20_STL + optional_impl() + : storage() + { + } + + //*************************************************************************** + /// Constructor with nullopt. + //*************************************************************************** + ETL_CONSTEXPR20_STL + optional_impl(etl::nullopt_t) + : storage() + { + } + +#include "private/diagnostic_uninitialized_push.h" + //*************************************************************************** + /// Copy constructor. + //*************************************************************************** + ETL_CONSTEXPR20_STL + optional_impl(const optional_impl& other) + { + if (other.has_value()) + { + storage.construct(other.value()); + } + } +#include "private/diagnostic_pop.h" + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Move constructor. + //*************************************************************************** + ETL_CONSTEXPR20_STL + optional_impl(optional_impl&& other) + { + if (other.has_value()) + { + storage.construct(etl::move(other.value())); + } + } +#endif + + //*************************************************************************** + /// Constructor from value type. + //*************************************************************************** + ETL_CONSTEXPR20_STL + optional_impl(const T& value_) + { + storage.construct(value_); + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Constructor from value type. + //*************************************************************************** + ETL_CONSTEXPR20_STL + optional_impl(T&& value_) + { + storage.construct(etl::move(value_)); + } +#endif + + //*************************************************************************** + /// Destructor. + //*************************************************************************** + ETL_CONSTEXPR20_STL + ~optional_impl() + { + storage.destroy(); + } + + //*************************************************************************** + /// Assignment operator from nullopt. + //*************************************************************************** + ETL_CONSTEXPR20_STL + optional_impl& operator =(etl::nullopt_t) + { + if (has_value()) + { + storage.destroy(); + } + + return *this; + } + + //*************************************************************************** + /// Assignment operator from optional_impl. + //*************************************************************************** + ETL_CONSTEXPR20_STL + optional_impl& operator =(const optional_impl& other) + { + if (this != &other) + { + if (other.has_value()) + { + storage.construct(other.value()); + } + else + { + storage.destroy(); + } + } + + return *this; + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Assignment operator from optional_impl. + //*************************************************************************** + ETL_CONSTEXPR20_STL + optional_impl& operator =(optional_impl&& other) + { + if (this != &other) + { + if (other.has_value()) + { + storage.construct(etl::move(other.value())); + } + else + { + storage.destroy(); + } + } + + return *this; + } +#endif + + //*************************************************************************** + /// Assignment operator from value type. + //*************************************************************************** + ETL_CONSTEXPR20_STL + optional_impl& operator =(const T& value_) + { + storage.construct(value_); + + return *this; + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Assignment operator from value type. + //*************************************************************************** + ETL_CONSTEXPR20_STL + optional_impl& operator =(T&& value_) + { + storage.construct(etl::move(value_)); + + return *this; + } +#endif + + public: + + //*************************************************************************** + /// Pointer operator. + //*************************************************************************** + ETL_CONSTEXPR20_STL + T* operator ->() + { +#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return &storage.u.value; + } + + //*************************************************************************** + /// Pointer operator. + //*************************************************************************** + ETL_CONSTEXPR20_STL + const T* operator ->() const + { +#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return &storage.u.value; + } + + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + ETL_CONSTEXPR20_STL + T& operator *() ETL_LVALUE_REF_QUALIFIER + { +#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return storage.u.value; + } + + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + ETL_CONSTEXPR20_STL + const T& operator *() const ETL_LVALUE_REF_QUALIFIER + { +#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return storage.u.value; + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + ETL_CONSTEXPR20_STL + T&& operator *()&& + { +#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return etl::move(storage.u.value); + } + + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + ETL_CONSTEXPR20_STL + const T&& operator *() const&& + { +#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return etl::move(storage.u.value); + } +#endif + + //*************************************************************************** + // Check whether optional contains value + //*************************************************************************** + ETL_CONSTEXPR20_STL + bool has_value() const ETL_NOEXCEPT + { + return storage.valid; + } + + //*************************************************************************** + /// Bool conversion operator. + //*************************************************************************** + ETL_CONSTEXPR20_STL + ETL_EXPLICIT operator bool() const + { + return has_value(); + } + + //*************************************************************************** + /// Get a reference to the value. + //*************************************************************************** + ETL_CONSTEXPR20_STL + T& value() ETL_LVALUE_REF_QUALIFIER + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return storage.u.value; + } + + //*************************************************************************** + /// Get a const reference to the value. + //*************************************************************************** + ETL_CONSTEXPR20_STL + const T& value() const ETL_LVALUE_REF_QUALIFIER + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return storage.u.value; + } + + //*************************************************************************** + /// Gets the value or a default if not valid. + //*************************************************************************** + ETL_CONSTEXPR20_STL + T value_or(const T& default_value) const ETL_LVALUE_REF_QUALIFIER + { + return has_value() ? value() : default_value; + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Get an rvalue reference to the value. + //*************************************************************************** + ETL_CONSTEXPR20_STL + T&& value()&& + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return etl::move(storage.u.value); + } + + //*************************************************************************** + /// Get a const rvalue reference to the value. + //*************************************************************************** + ETL_CONSTEXPR20_STL + const T&& value() const&& + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return etl::move(storage.u.value); + } + + //*************************************************************************** + /// Gets the value or a default if not valid. + //*************************************************************************** + template + ETL_CONSTEXPR20_STL + etl::enable_if_t::value, T> + value_or(U&& default_value) const& + { + return has_value() ? value() : etl::forward(default_value); + } + + //*************************************************************************** + /// Gets the value or a default if not valid. + //*************************************************************************** + template + ETL_CONSTEXPR20_STL + etl::enable_if_t::value, T> + value_or(U&& default_value)&& + { + return has_value() ? etl::move(value()) : etl::forward(default_value); + } +#endif + + //*************************************************************************** + /// Swaps this value with another. + //*************************************************************************** + ETL_CONSTEXPR20_STL + void swap(optional_impl& other) + { + optional_impl temp(*this); + *this = other; + other = temp; + } + + //*************************************************************************** + /// Reset back to invalid. + //*************************************************************************** + ETL_CONSTEXPR20_STL + void reset() + { + storage.destroy(); + } + +#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_OPTIONAL_FORCE_CPP03_IMPLEMENTATION) + //************************************************************************* + /// Emplaces a value. + ///\param args The arguments to construct with. + //************************************************************************* + template + ETL_CONSTEXPR20_STL + void emplace(TArgs&& ... args) + { + storage.construct(etl::forward(args)...); + } +#else + //************************************************************************* + /// Emplaces a value. + /// 1 parameter. + //************************************************************************* + T& emplace() + { + if (has_value()) + { + // Destroy the old one. + storage.destroy(); + } + + T* p = ::new (&storage.u.value) T(); + storage.valid = true; + + return *p; + } + + //************************************************************************* + /// Emplaces a value. + /// 1 parameter. + //************************************************************************* + template + T& emplace(const T1& value1) + { + if (has_value()) + { + // Destroy the old one. + storage.destroy(); + } + + T* p = ::new (&storage.u.value) T(value1); + storage.valid = true; + + return *p; + } + + //************************************************************************* + /// Emplaces a value. + /// 2 parameters. + //************************************************************************* + template + T& emplace(const T1& value1, const T2& value2) + { + if (has_value()) + { + // Destroy the old one. + storage.destroy(); + } + + T* p = ::new (&storage.u.value) T(value1, value2); + storage.valid = true; + + return *p; + } + + //************************************************************************* + /// Emplaces a value. + /// 3 parameters. + //************************************************************************* + template + T& emplace(const T1& value1, const T2& value2, const T3& value3) + { + if (has_value()) + { + // Destroy the old one. + storage.destroy(); + } + + T* p = ::new (&storage.u.value) T(value1, value2, value3); + storage.valid = true; + + return *p; + } + + //************************************************************************* + /// Emplaces a value. + /// 4 parameters. + //************************************************************************* + template + T& emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + if (has_value()) + { + // Destroy the old one. + storage.destroy(); + } + + T* p = ::new (&storage.u.value) T(value1, value2, value3, value4); + storage.valid = true; + + return *p; + } +#endif + + private: + + struct dummy_t {}; + + //************************************* + // The storage for the optional value. + //************************************* + struct storage_type + { + //******************************* + ETL_CONSTEXPR20_STL + storage_type() + : u() + , valid(false) + { + } + + //******************************* + ETL_CONSTEXPR20_STL + void construct(const T& value_) + { + if (valid) + { + etl::destroy_at(&u.value); + } + + etl::construct_at(&u.value, value_); + valid = true; + } + +#if ETL_USING_CPP11 + //******************************* + ETL_CONSTEXPR20_STL + void construct(T&& value_) + { + if (valid) + { + etl::destroy_at(&u.value); + } + + etl::construct_at(&u.value, etl::move(value_)); + valid = true; + } + + //******************************* + template + ETL_CONSTEXPR20_STL + void construct(TArgs&&... args) + { + if (valid) + { + etl::destroy_at(&u.value); + } + + etl::construct_at(&u.value, etl::forward(args)...); + valid = true; + } +#endif + + //******************************* + ETL_CONSTEXPR20_STL + void destroy() + { + if (valid) + { + etl::destroy_at(&u.value); + valid = false; + } + } + + //******************************* + union union_type + { + ETL_CONSTEXPR20_STL + union_type() + : dummy() + { + } + + ETL_CONSTEXPR20_STL + ~union_type() + { + } + + dummy_t dummy; + T value; + } u; + + bool valid; + }; + + storage_type storage; + }; + + //***************************************************************************** + // Implementation for trivial types. + //***************************************************************************** + template + class optional_impl + { + protected: + + typedef T value_type; + + //*************************************************************************** + /// Constructor. + //*************************************************************************** + ETL_CONSTEXPR14 + optional_impl() + : storage() + { + } + + //*************************************************************************** + /// Constructor with nullopt. + //*************************************************************************** + ETL_CONSTEXPR14 + optional_impl(etl::nullopt_t) + : storage() + { + } + +#include "private/diagnostic_uninitialized_push.h" + //*************************************************************************** + /// Copy constructor. + //*************************************************************************** + ETL_CONSTEXPR14 + optional_impl(const optional_impl& other) + { + if (other.has_value()) + { + storage.construct(other.value()); + } + } +#include "private/diagnostic_pop.h" + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Move constructor. + //*************************************************************************** + ETL_CONSTEXPR14 + optional_impl(optional_impl&& other) + { + if (other.has_value()) + { + storage.construct(etl::move(other.value())); + } + } +#endif + + //*************************************************************************** + /// Constructor from value type. + //*************************************************************************** + ETL_CONSTEXPR14 + optional_impl(const T& value_) + { + storage.construct(value_); + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Constructor from value type. + //*************************************************************************** + ETL_CONSTEXPR14 + optional_impl(T&& value_) + { + storage.construct(etl::move(value_)); + } +#endif + + //*************************************************************************** + /// Assignment operator from nullopt. + //*************************************************************************** + ETL_CONSTEXPR14 + optional_impl& operator =(etl::nullopt_t) + { + if (has_value()) + { + storage.destroy(); + } + + return *this; + } + + //*************************************************************************** + /// Assignment operator from optional_impl. + //*************************************************************************** + ETL_CONSTEXPR14 + optional_impl& operator =(const optional_impl& other) + { + if (this != &other) + { + if (other.has_value()) + { + storage.construct(other.value()); + } + else + { + storage.destroy(); + } + } + + return *this; + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Assignment operator from optional_impl. + //*************************************************************************** + ETL_CONSTEXPR14 + optional_impl& operator =(optional_impl&& other) + { + if (this != &other) + { + if (other.has_value()) + { + storage.construct(etl::move(other.value())); + } + else + { + storage.destroy(); + } + } + + return *this; + } +#endif + + //*************************************************************************** + /// Assignment operator from value type. + //*************************************************************************** + ETL_CONSTEXPR14 + optional_impl& operator =(const T& value_) + { + storage.construct(value_); + + return *this; + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Assignment operator from value type. + //*************************************************************************** + ETL_CONSTEXPR14 + optional_impl& operator =(T&& value_) + { + storage.construct(etl::move(value_)); + + return *this; + } +#endif + + public: + + //*************************************************************************** + /// Pointer operator. + //*************************************************************************** + ETL_CONSTEXPR14 + T* operator ->() + { +#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return &storage.u.value; + } + + //*************************************************************************** + /// Pointer operator. + //*************************************************************************** + ETL_CONSTEXPR14 + const T* operator ->() const + { +#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return &storage.u.value; + } + + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + ETL_CONSTEXPR14 + T& operator *() ETL_LVALUE_REF_QUALIFIER + { +#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return storage.u.value; + } + + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + ETL_CONSTEXPR14 + const T& operator *() const ETL_LVALUE_REF_QUALIFIER + { +#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return storage.u.value; + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + ETL_CONSTEXPR14 + T&& operator *()&& + { +#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return etl::move(storage.u.value); + } + + //*************************************************************************** + /// Dereference operator. + //*************************************************************************** + ETL_CONSTEXPR14 + const T&& operator *() const&& + { +#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return etl::move(storage.u.value); + } +#endif + + //*************************************************************************** + // Check whether optional contains value + //*************************************************************************** + ETL_CONSTEXPR14 + bool has_value() const ETL_NOEXCEPT + { + return storage.valid; + } + + //*************************************************************************** + /// Bool conversion operator. + //*************************************************************************** + ETL_CONSTEXPR14 + ETL_EXPLICIT operator bool() const + { + return has_value(); + } + + //*************************************************************************** + /// Get a reference to the value. + //*************************************************************************** + ETL_CONSTEXPR14 + T& value() ETL_LVALUE_REF_QUALIFIER + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return storage.u.value; + } + + //*************************************************************************** + /// Get a const reference to the value. + //*************************************************************************** + ETL_CONSTEXPR14 + const T& value() const ETL_LVALUE_REF_QUALIFIER + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return storage.u.value; + } + + //*************************************************************************** + /// Gets the value or a default if not valid. + //*************************************************************************** + ETL_CONSTEXPR14 + T value_or(const T& default_value) const ETL_LVALUE_REF_QUALIFIER + { + return has_value() ? value() : default_value; + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Get an rvalue reference to the value. + //*************************************************************************** + ETL_CONSTEXPR14 + T&& value()&& + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return etl::move(storage.u.value); + } + + //*************************************************************************** + /// Get a const rvalue reference to the value. + //*************************************************************************** + ETL_CONSTEXPR14 + const T&& value() const&& + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); +#endif + + return etl::move(storage.u.value); + } + + //*************************************************************************** + /// Gets the value or a default if not valid. + //*************************************************************************** + template + ETL_CONSTEXPR14 + etl::enable_if_t::value, T> + value_or(U&& default_value) const& + { + return has_value() ? value() : etl::forward(default_value); + } + + //*************************************************************************** + /// Gets the value or a default if not valid. + //*************************************************************************** + template + ETL_CONSTEXPR14 + etl::enable_if_t::value, T> + value_or(U&& default_value)&& + { + return has_value() ? etl::move(value()) : etl::forward(default_value); + } +#endif + + //*************************************************************************** + /// Swaps this value with another. + //*************************************************************************** + ETL_CONSTEXPR14 + void swap(optional_impl& other) + { + optional_impl temp(*this); + *this = other; + other = temp; + } + + //*************************************************************************** + /// Reset back to invalid. + //*************************************************************************** + ETL_CONSTEXPR14 + void reset() + { + storage.destroy(); + } + +#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_OPTIONAL_FORCE_CPP03_IMPLEMENTATION) + //************************************************************************* + /// Emplaces a value. + ///\param args The arguments to construct with. + //************************************************************************* + template + ETL_CONSTEXPR14 + void emplace(TArgs&& ... args) + { + storage.construct(etl::forward(args)...); + } +#else + //************************************************************************* + /// Emplaces a value. + /// 1 parameter. + //************************************************************************* + T& emplace() + { + if (has_value()) + { + // Destroy the old one. + storage.destroy(); + } + + T* p = ::new (&storage.u.value) T(); + storage.valid = true; + + return *p; + } + + //************************************************************************* + /// Emplaces a value. + /// 1 parameter. + //************************************************************************* + template + T& emplace(const T1& value1) + { + if (has_value()) + { + // Destroy the old one. + storage.destroy(); + } + + T* p = ::new (&storage.u.value) T(value1); + storage.valid = true; + + return *p; + } + + //************************************************************************* + /// Emplaces a value. + /// 2 parameters. + //************************************************************************* + template + T& emplace(const T1& value1, const T2& value2) + { + if (has_value()) + { + // Destroy the old one. + storage.destroy(); + } + + T* p = ::new (&storage.u.value) T(value1, value2); + storage.valid = true; + + return *p; + } + + //************************************************************************* + /// Emplaces a value. + /// 3 parameters. + //************************************************************************* + template + T& emplace(const T1& value1, const T2& value2, const T3& value3) + { + if (has_value()) + { + // Destroy the old one. + storage.destroy(); + } + + T* p = ::new (&storage.u.value) T(value1, value2, value3); + storage.valid = true; + + return *p; + } + + //************************************************************************* + /// Emplaces a value. + /// 4 parameters. + //************************************************************************* + template + T& emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + if (has_value()) + { + // Destroy the old one. + storage.destroy(); + } + + T* p = ::new (&storage.u.value) T(value1, value2, value3, value4); + storage.valid = true; + + return *p; + } +#endif + + private: + + struct dummy_t {}; + + //************************************* + // The storage for the optional value. + //************************************* + struct storage_type + { + //******************************* + ETL_CONSTEXPR14 + storage_type() + : u() + , valid(false) + { + } + + //******************************* + ETL_CONSTEXPR14 + void construct(const T& value_) + { + u.value = value_; + valid = true; + } + +#if ETL_USING_CPP11 + //******************************* + ETL_CONSTEXPR14 + void construct(T&& value_) + { + u.value = value_; + valid = true; + } + + //******************************* + template + ETL_CONSTEXPR14 + void construct(TArgs&&... args) + { + u.value = T(etl::forward(args)...); + valid = true; + } +#endif + + //******************************* + ETL_CONSTEXPR14 + void destroy() + { + valid = false; + } + + //******************************* + union union_type + { + ETL_CONSTEXPR14 + union_type() + : dummy() + { + } + + dummy_t dummy; + T value; + } u; + + bool valid; + }; + + storage_type storage; + }; + } + +#define ETL_OPTIONAL_ENABLE_CPP14 typename etl::enable_if< etl::is_pod::value, int>::type = 0 +#define ETL_OPTIONAL_ENABLE_CPP20_STL typename etl::enable_if::value, int>::type = 0 + +#define ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 ETL_CONSTEXPR14 typename etl::enable_if< etl::is_pod::value, bool>::type +#define ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL ETL_CONSTEXPR20_STL typename etl::enable_if::value, bool>::type + //***************************************************************************** /// An optional type. /// If the optional type is not initialised then a type is not constructed. @@ -105,97 +1233,225 @@ namespace etl ///\ingroup utilities //***************************************************************************** template - class optional + class optional : public private_optional::optional_impl { + private: + + typedef private_optional::optional_impl impl_t; + public: typedef T value_type; +#if ETL_USING_CPP11 //*************************************************************************** /// Constructor. //*************************************************************************** + template + ETL_CONSTEXPR14 + optional() + : impl_t() + { + } + + //*************************************************************************** + /// Constructor. + //*************************************************************************** + template ETL_CONSTEXPR20_STL optional() - : storage() + : impl_t() + { + } +#else + optional() + : impl_t() + { + } +#endif + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Constructor with nullopt. + //*************************************************************************** + template + ETL_CONSTEXPR14 + optional(etl::nullopt_t) + : impl_t(etl::nullopt_t{}) { } //*************************************************************************** /// Constructor with nullopt. //*************************************************************************** + template ETL_CONSTEXPR20_STL optional(etl::nullopt_t) - : storage() + : impl_t(etl::nullopt_t{}) { } +#else + //*************************************************************************** + /// Constructor with nullopt. + //*************************************************************************** + optional(etl::nullopt_t) + : impl_t(etl::nullopt_t{}) + { + } +#endif #include "private/diagnostic_uninitialized_push.h" +#if ETL_USING_CPP11 //*************************************************************************** /// Copy constructor. //*************************************************************************** + template + ETL_CONSTEXPR14 + optional(const optional& other) + : impl_t(other) + { + } + + //*************************************************************************** + /// Copy constructor. + //*************************************************************************** + template ETL_CONSTEXPR20_STL optional(const optional& other) + : impl_t(other) { - if (other.has_value()) - { - storage.construct(other.value()); - } } +#else + //*************************************************************************** + /// Copy constructor. + //*************************************************************************** + optional(const optional& other) + : impl_t(other) + { + } +#endif #include "private/diagnostic_pop.h" #if ETL_USING_CPP11 //*************************************************************************** /// Move constructor. //*************************************************************************** - ETL_CONSTEXPR20_STL + template + ETL_CONSTEXPR14 optional(optional&& other) + : impl_t(other) { - if (other.has_value()) - { - storage.construct(etl::move(other.value())); - } } -#endif //*************************************************************************** - /// Constructor from value type. + /// Move constructor. //*************************************************************************** + template ETL_CONSTEXPR20_STL - optional(const T& value_) + optional(optional&& other) + : impl_t(other) { - storage.construct(value_); } +#endif #if ETL_USING_CPP11 //*************************************************************************** - /// Constructor from value type. + /// Construct from value type. //*************************************************************************** - ETL_CONSTEXPR20_STL - optional(T&& value_) + template + ETL_CONSTEXPR14 + optional(const T& value_) + : impl_t(value_) + { + } + + //*************************************************************************** + /// Construct from value type. + //*************************************************************************** + template + ETL_CONSTEXPR20_STL + optional(const T& value_) + : impl_t(value_) + { + } +#else + //*************************************************************************** + /// Construct from value type. + //*************************************************************************** + optional(const T& value_) + : impl_t(value_) { - storage.construct(etl::move(value_)); } #endif + +#if ETL_USING_CPP11 //*************************************************************************** - /// Destructor. + /// Move construct from value type. //*************************************************************************** - ETL_CONSTEXPR20_STL - ~optional() + template + ETL_CONSTEXPR14 + optional(T&& value_) + : impl_t(etl::move(value_)) { - storage.destroy(); + } + + //*************************************************************************** + /// Move construct from value type. + //*************************************************************************** + template + ETL_CONSTEXPR20_STL + optional(T&& value_) + : impl_t(etl::move(value_)) + { + } +#endif + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Assignment operator from nullopt. + //*************************************************************************** + template + ETL_CONSTEXPR14 + optional& operator =(etl::nullopt_t) + { + impl_t::operator=(etl::nullopt_t{}); + + return *this; } //*************************************************************************** /// Assignment operator from nullopt. //*************************************************************************** + template ETL_CONSTEXPR20_STL optional& operator =(etl::nullopt_t) { - if (has_value()) - { - storage.destroy(); - } + impl_t::operator=(etl::nullopt_t{}); + + return *this; + } +#else + //*************************************************************************** + /// Assignment operator from nullopt. + //*************************************************************************** + optional& operator =(etl::nullopt_t) + { + impl_t::operator=(etl::nullopt_t{}); + + return *this; + } +#endif + +#if ETL_USING_CPP11 + //*************************************************************************** + /// Assignment operator from optional. + //*************************************************************************** + template + ETL_CONSTEXPR14 + optional& operator =(const optional& other) + { + impl_t::operator=(other); return *this; } @@ -203,558 +1459,113 @@ namespace etl //*************************************************************************** /// Assignment operator from optional. //*************************************************************************** + template ETL_CONSTEXPR20_STL optional& operator =(const optional& other) { - if (this != &other) - { - if (other.has_value()) - { - storage.construct(other.value()); - } - else - { - storage.destroy(); - } - } + impl_t::operator=(other); return *this; } - -#if ETL_USING_CPP11 +#else //*************************************************************************** /// Assignment operator from optional. //*************************************************************************** - ETL_CONSTEXPR20_STL - optional& operator =(optional&& other) + optional& operator =(const optional& other) { - if (this != &other) - { - if (other.has_value()) - { - storage.construct(etl::move(other.value())); - } - else - { - storage.destroy(); - } - } + impl_t::operator=(other); return *this; } #endif +#if ETL_USING_CPP11 + //*************************************************************************** + /// Move assignment operator from optional. + //*************************************************************************** + template + ETL_CONSTEXPR14 + optional& operator =(optional&& other) + { + impl_t::operator=(etl::move(other)); + + return *this; + } + + //*************************************************************************** + /// Move assignment operator from optional. + //*************************************************************************** + template + ETL_CONSTEXPR20_STL + optional& operator =(optional&& other) + { + impl_t::operator=(etl::move(other)); + + return *this; + } +#endif + +#if ETL_USING_CPP11 //*************************************************************************** /// Assignment operator from value type. //*************************************************************************** + template + ETL_CONSTEXPR14 + optional& operator =(const T& value_) + { + impl_t::operator=(value_); + + return *this; + } + + //*************************************************************************** + /// Assignment operator from value type. + //*************************************************************************** + template ETL_CONSTEXPR20_STL optional& operator =(const T& value_) { - storage.construct(value_); + impl_t::operator=(value_); return *this; } - -#if ETL_USING_CPP11 +#else //*************************************************************************** /// Assignment operator from value type. //*************************************************************************** - ETL_CONSTEXPR20_STL - optional& operator =(T&& value_) + optional& operator =(const T& value_) { - storage.construct(etl::move(value_)); + impl_t::operator=(value_); return *this; } #endif - //*************************************************************************** - /// Pointer operator. - //*************************************************************************** - ETL_CONSTEXPR20_STL - T* operator ->() - { -#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) - ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); -#endif - - return &storage.u.value; - } - - //*************************************************************************** - /// Pointer operator. - //*************************************************************************** - ETL_CONSTEXPR20_STL - const T* operator ->() const - { -#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) - ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); -#endif - - return &storage.u.value; - } - - //*************************************************************************** - /// Dereference operator. - //*************************************************************************** - ETL_CONSTEXPR20_STL - T& operator *() ETL_LVALUE_REF_QUALIFIER - { -#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) - ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); -#endif - - return storage.u.value; - } - - //*************************************************************************** - /// Dereference operator. - //*************************************************************************** - ETL_CONSTEXPR20_STL - const T& operator *() const ETL_LVALUE_REF_QUALIFIER - { -#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) - ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); -#endif - - return storage.u.value; - } - #if ETL_USING_CPP11 //*************************************************************************** - /// Dereference operator. + /// Move assignment operator from value type. //*************************************************************************** - ETL_CONSTEXPR20_STL - T&& operator *()&& + template + ETL_CONSTEXPR14 + optional& operator =(T&& value_) { -#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) - ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); -#endif + impl_t::operator=(etl::move(value_)); - return etl::move(storage.u.value); + return *this; } //*************************************************************************** - /// Dereference operator. + /// Move assignment operator from value type. //*************************************************************************** + template ETL_CONSTEXPR20_STL - const T&& operator *() const&& + optional& operator =(T&& value_) { -#if ETL_IS_DEBUG_BUILD && !(ETL_USING_CPP20 && ETL_USING_STL) - ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); -#endif + impl_t::operator=(etl::move(value_)); - return etl::move(storage.u.value); + return *this; } #endif - - //*************************************************************************** - // Check whether optional contains value - //*************************************************************************** - ETL_CONSTEXPR20_STL - bool has_value() const ETL_NOEXCEPT - { - return storage.valid; - } - - //*************************************************************************** - /// Bool conversion operator. - //*************************************************************************** - ETL_CONSTEXPR20_STL - ETL_EXPLICIT operator bool() const - { - return has_value(); - } - - //*************************************************************************** - /// Get a reference to the value. - //*************************************************************************** - ETL_CONSTEXPR20_STL - T& value() ETL_LVALUE_REF_QUALIFIER - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); -#endif - - return storage.u.value; - } - - //*************************************************************************** - /// Get a const reference to the value. - //*************************************************************************** - ETL_CONSTEXPR20_STL - const T& value() const ETL_LVALUE_REF_QUALIFIER - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); -#endif - - return storage.u.value; - } - - //*************************************************************************** - /// Gets the value or a default if not valid. - //*************************************************************************** - ETL_CONSTEXPR20_STL - T value_or(const T& default_value) const ETL_LVALUE_REF_QUALIFIER - { - return has_value() ? value() : default_value; - } - -#if ETL_USING_CPP11 - //*************************************************************************** - /// Get an rvalue reference to the value. - //*************************************************************************** - ETL_CONSTEXPR20_STL - T&& value()&& - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); -#endif - - return etl::move(storage.u.value); - } - - //*************************************************************************** - /// Get a const rvalue reference to the value. - //*************************************************************************** - ETL_CONSTEXPR20_STL - const T&& value() const&& - { -#if ETL_IS_DEBUG_BUILD - ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); -#endif - - return etl::move(storage.u.value); - } - - //*************************************************************************** - /// Gets the value or a default if not valid. - //*************************************************************************** - template - ETL_CONSTEXPR20_STL - etl::enable_if_t::value, T> - value_or(U&& default_value) const& - { - return has_value() ? value() : etl::forward(default_value); - } - - //*************************************************************************** - /// Gets the value or a default if not valid. - //*************************************************************************** - template - ETL_CONSTEXPR20_STL - etl::enable_if_t::value, T> - value_or(U&& default_value) && - { - return has_value() ? etl::move(value()) : etl::forward(default_value); - } -#endif - - //*************************************************************************** - /// Swaps this value with another. - //*************************************************************************** - ETL_CONSTEXPR20_STL - void swap(optional& other) - { - optional temp(*this); - *this = other; - other = temp; - } - - //*************************************************************************** - /// Reset back to invalid. - //*************************************************************************** - ETL_CONSTEXPR20_STL - void reset() - { - storage.destroy(); - } - -#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_OPTIONAL_FORCE_CPP03_IMPLEMENTATION) - //************************************************************************* - /// Emplaces a value. - ///\param args The arguments to construct with. - //************************************************************************* - template - ETL_CONSTEXPR20_STL - void emplace(TArgs&& ... args) - { - storage.construct(etl::forward(args)...); - } -#else - //************************************************************************* - /// Emplaces a value. - /// 1 parameter. - //************************************************************************* - T& emplace() - { - if (has_value()) - { - // Destroy the old one. - storage.destroy(); - } - - T* p = ::new (&storage.u.value) T(); - storage.valid = true; - - return *p; - } - - //************************************************************************* - /// Emplaces a value. - /// 1 parameter. - //************************************************************************* - template - T& emplace(const T1& value1) - { - if (has_value()) - { - // Destroy the old one. - storage.destroy(); - } - - T* p = ::new (&storage.u.value) T(value1); - storage.valid = true; - - return *p; - } - - //************************************************************************* - /// Emplaces a value. - /// 2 parameters. - //************************************************************************* - template - T& emplace(const T1& value1, const T2& value2) - { - if (has_value()) - { - // Destroy the old one. - storage.destroy(); - } - - T* p = ::new (&storage.u.value) T(value1, value2); - storage.valid = true; - - return *p; - } - - //************************************************************************* - /// Emplaces a value. - /// 3 parameters. - //************************************************************************* - template - T& emplace(const T1& value1, const T2& value2, const T3& value3) - { - if (has_value()) - { - // Destroy the old one. - storage.destroy(); - } - - T* p = ::new (&storage.u.value) T(value1, value2, value3); - storage.valid = true; - - return *p; - } - - //************************************************************************* - /// Emplaces a value. - /// 4 parameters. - //************************************************************************* - template - T& emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4) - { - if (has_value()) - { - // Destroy the old one. - storage.destroy(); - } - - T* p = ::new (&storage.u.value) T(value1, value2, value3, value4); - storage.valid = true; - - return *p; - } -#endif - - private: - - struct dummy_t {}; - - template ::value> - struct storage_type; - - //************************************* - // Non-POD - //************************************* - template - struct storage_type - { - //******************************* - ETL_CONSTEXPR20_STL - storage_type() - : u() - , valid(false) - { - } - - //******************************* - ETL_CONSTEXPR20_STL - ~storage_type() - { - destroy(); - } - - //******************************* - ETL_CONSTEXPR20_STL - void construct(const TValue& value_) - { - if (valid) - { - etl::destroy_at(&u.value); - } - - etl::construct_at(&u.value, value_); - valid = true; - } - -#if ETL_USING_CPP11 - //******************************* - ETL_CONSTEXPR20_STL - void construct(TValue&& value_) - { - if (valid) - { - etl::destroy_at(&u.value); - } - - etl::construct_at(&u.value, etl::move(value_)); - valid = true; - } - - //******************************* - template - ETL_CONSTEXPR20_STL - void construct(TArgs&&... args) - { - if (valid) - { - etl::destroy_at(&u.value); - } - - etl::construct_at(&u.value, etl::forward(args)...); - valid = true; - } -#endif - - //******************************* - ETL_CONSTEXPR20_STL - void destroy() - { - if (valid) - { - etl::destroy_at(&u.value); - valid = false; - } - } - - //******************************* - union union_type - { - ETL_CONSTEXPR20_STL - union_type() - : dummy() - { - } - - ETL_CONSTEXPR20_STL - ~union_type() - { - } - - dummy_t dummy; - TValue value; - } u; - - bool valid; - }; - - //************************************* - // POD - //************************************* - template - struct storage_type - { - //******************************* - ETL_CONSTEXPR20_STL - storage_type() - : valid(false) - { - } - - //******************************* - ETL_CONSTEXPR20_STL - ~storage_type() - { - } - - //******************************* - ETL_CONSTEXPR20_STL - void construct(const TValue& value_) - { - u.value = value_; - valid = true; - } - -#if ETL_USING_CPP11 - //******************************* - ETL_CONSTEXPR20_STL - void construct(TValue&& value_) - { - u.value = value_; - valid = true; - } - - //******************************* - template - ETL_CONSTEXPR20_STL - void construct(TArgs&&... args) - { - u.value = TValue(etl::forward(args)...); - valid = true; - } -#endif - - //******************************* - ETL_CONSTEXPR20_STL - void destroy() - { - valid = false; - } - - //******************************* - union union_type - { - ETL_CONSTEXPR20_STL - union_type() - : dummy() - { - } - - ETL_CONSTEXPR20_STL - ~union_type() - { - } - - dummy_t dummy; - TValue value; - } u; - - bool valid; - }; - - storage_type storage; }; #include "private/diagnostic_uninitialized_push.h" @@ -763,7 +1574,7 @@ namespace etl /// Equality operator. cppreference 1 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator ==(const etl::optional& lhs, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator ==(const etl::optional& lhs, const etl::optional& rhs) { if (lhs.has_value() != rhs.has_value()) { @@ -780,10 +1591,39 @@ namespace etl } //*************************************************************************** - /// Equality operator. cppreference 2 + /// Equality operator. cppreference 1 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator !=(const etl::optional& lhs, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator ==(const etl::optional& lhs, const etl::optional& rhs) + { + if (lhs.has_value() != rhs.has_value()) + { + return false; + } + else if (!lhs.has_value() && !rhs.has_value()) + { + return true; + } + else + { + return lhs.value() == rhs.value(); + } + } + + //*************************************************************************** + /// Inequality operator. cppreference 2 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator !=(const etl::optional& lhs, const etl::optional& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// Inequality operator. cppreference 2 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator !=(const etl::optional& lhs, const etl::optional& rhs) { return !(lhs == rhs); } @@ -792,7 +1632,27 @@ namespace etl /// Less than operator. cppreference 3 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator <(const etl::optional& lhs, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator <(const etl::optional& lhs, const etl::optional& rhs) + { + if (!rhs.has_value()) + { + return false; + } + else if (!lhs.has_value()) + { + return true; + } + else + { + return lhs.value() < rhs.value(); + } + } + + //*************************************************************************** + /// Less than operator. cppreference 3 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator <(const etl::optional& lhs, const etl::optional& rhs) { if (!rhs.has_value()) { @@ -812,7 +1672,16 @@ namespace etl /// Less than equal operator. cppreference 4 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator <=(const etl::optional& lhs, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator <=(const etl::optional& lhs, const etl::optional& rhs) + { + return !(rhs < lhs); + } + + //*************************************************************************** + /// Less than equal operator. cppreference 4 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator <=(const etl::optional& lhs, const etl::optional& rhs) { return !(rhs < lhs); } @@ -821,7 +1690,16 @@ namespace etl /// greater than operator. cppreference 5 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator >(const etl::optional& lhs, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator >(const etl::optional& lhs, const etl::optional& rhs) + { + return (rhs < lhs); + } + + //*************************************************************************** + /// greater than operator. cppreference 5 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator >(const etl::optional& lhs, const etl::optional& rhs) { return (rhs < lhs); } @@ -830,7 +1708,16 @@ namespace etl /// greater than equal operator. cppreference 6 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator >=(const etl::optional& lhs, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator >=(const etl::optional& lhs, const etl::optional& rhs) + { + return !(lhs < rhs); + } + + //*************************************************************************** + /// greater than equal operator. cppreference 6 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator >=(const etl::optional& lhs, const etl::optional& rhs) { return !(lhs < rhs); } @@ -839,7 +1726,16 @@ namespace etl /// Equality operator. cppreference 7 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator ==(const etl::optional& lhs, etl::nullopt_t) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator ==(const etl::optional& lhs, etl::nullopt_t) + { + return !lhs.has_value(); + } + + //*************************************************************************** + /// Equality operator. cppreference 7 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator ==(const etl::optional& lhs, etl::nullopt_t) { return !lhs.has_value(); } @@ -848,7 +1744,16 @@ namespace etl /// Equality operator. cppreference 8 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator ==(etl::nullopt_t, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator ==(etl::nullopt_t, const etl::optional& rhs) + { + return !rhs.has_value(); + } + + //*************************************************************************** + /// Equality operator. cppreference 8 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator ==(etl::nullopt_t, const etl::optional& rhs) { return !rhs.has_value(); } @@ -857,7 +1762,16 @@ namespace etl /// Inequality operator. cppreference 9 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator !=(const etl::optional& lhs, etl::nullopt_t) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator !=(const etl::optional& lhs, etl::nullopt_t) + { + return !(lhs == etl::nullopt); + } + + //*************************************************************************** + /// Inequality operator. cppreference 9 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator !=(const etl::optional& lhs, etl::nullopt_t) { return !(lhs == etl::nullopt); } @@ -866,7 +1780,16 @@ namespace etl /// Inequality operator. cppreference 10 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator !=(etl::nullopt_t , const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator !=(etl::nullopt_t , const etl::optional& rhs) + { + return !(etl::nullopt == rhs); + } + + //*************************************************************************** + /// Inequality operator. cppreference 10 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator !=(etl::nullopt_t, const etl::optional& rhs) { return !(etl::nullopt == rhs); } @@ -875,7 +1798,16 @@ namespace etl /// Less than operator. cppreference 11 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator <(const etl::optional&, etl::nullopt_t) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator <(const etl::optional&, etl::nullopt_t) + { + return false; + } + + //*************************************************************************** + /// Less than operator. cppreference 11 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator <(const etl::optional&, etl::nullopt_t) { return false; } @@ -884,7 +1816,16 @@ namespace etl /// Less than operator. cppreference 12 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator <(etl::nullopt_t, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator <(etl::nullopt_t, const etl::optional& rhs) + { + return rhs.has_value(); + } + + //*************************************************************************** + /// Less than operator. cppreference 12 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator <(etl::nullopt_t, const etl::optional& rhs) { return rhs.has_value(); } @@ -893,7 +1834,16 @@ namespace etl /// Less than equal operator. cppreference 13 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator <=(const etl::optional& lhs, etl::nullopt_t) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator <=(const etl::optional& lhs, etl::nullopt_t) + { + return !lhs.has_value(); + } + + //*************************************************************************** + /// Less than equal operator. cppreference 13 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator <=(const etl::optional& lhs, etl::nullopt_t) { return !lhs.has_value(); } @@ -902,7 +1852,16 @@ namespace etl /// Less than equal operator. cppreference 14 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator <=(etl::nullopt_t, const etl::optional&) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator <=(etl::nullopt_t, const etl::optional&) + { + return true; + } + + //*************************************************************************** + /// Less than equal operator. cppreference 14 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator <=(etl::nullopt_t, const etl::optional&) { return true; } @@ -911,7 +1870,16 @@ namespace etl /// Greater than operator. cppreference 15 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator >(const etl::optional& lhs, etl::nullopt_t) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator >(const etl::optional& lhs, etl::nullopt_t) + { + return lhs.has_value(); + } + + //*************************************************************************** + /// Greater than operator. cppreference 15 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator >(const etl::optional& lhs, etl::nullopt_t) { return lhs.has_value(); } @@ -920,7 +1888,16 @@ namespace etl /// Greater than operator. cppreference 16 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator >(etl::nullopt_t, const etl::optional&) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator >(etl::nullopt_t, const etl::optional&) + { + return false; + } + + //*************************************************************************** + /// Greater than operator. cppreference 16 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator >(etl::nullopt_t, const etl::optional&) { return false; } @@ -929,7 +1906,16 @@ namespace etl /// Greater than equal operator. cppreference 17 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator >=(const etl::optional&, etl::nullopt_t) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator >=(const etl::optional&, etl::nullopt_t) + { + return true; + } + + //*************************************************************************** + /// Greater than equal operator. cppreference 17 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator >=(const etl::optional&, etl::nullopt_t) { return true; } @@ -938,7 +1924,16 @@ namespace etl /// Greater than equal operator. cppreference 18 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator >=(etl::nullopt_t, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator >=(etl::nullopt_t, const etl::optional& rhs) + { + return !rhs.has_value(); + } + + //*************************************************************************** + /// Greater than equal operator. cppreference 18 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator >=(etl::nullopt_t, const etl::optional& rhs) { return !rhs.has_value(); } @@ -947,7 +1942,16 @@ namespace etl /// Equality operator. cppreference 19 //************************************************************************** template - ETL_CONSTEXPR20_STL bool operator ==(const etl::optional& lhs, const U& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator ==(const etl::optional& lhs, const U& rhs) + { + return lhs.has_value() ? lhs.value() == rhs : false; + } + + //*************************************************************************** + /// Equality operator. cppreference 19 + //************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator ==(const etl::optional& lhs, const U& rhs) { return lhs.has_value() ? lhs.value() == rhs : false; } @@ -956,7 +1960,16 @@ namespace etl /// Inequality operator. cppreference 21 //************************************************************************** template - ETL_CONSTEXPR20_STL bool operator !=(const etl::optional& lhs, const U& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator !=(const etl::optional& lhs, const U& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// Inequality operator. cppreference 21 + //************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator !=(const etl::optional& lhs, const U& rhs) { return !(lhs == rhs); } @@ -965,7 +1978,16 @@ namespace etl /// Equality operator. cppreference 20 //************************************************************************** template - ETL_CONSTEXPR20_STL bool operator ==(const U& lhs, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator ==(const U& lhs, const etl::optional& rhs) + { + return rhs.has_value() ? rhs.value() == lhs : false; + } + + //*************************************************************************** + /// Equality operator. cppreference 20 + //************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator ==(const U& lhs, const etl::optional& rhs) { return rhs.has_value() ? rhs.value() == lhs : false; } @@ -974,7 +1996,16 @@ namespace etl /// Inequality operator. cppreference 22 //************************************************************************** template - ETL_CONSTEXPR20_STL bool operator !=(const U& lhs, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator !=(const U& lhs, const etl::optional& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// Inequality operator. cppreference 22 + //************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator !=(const U& lhs, const etl::optional& rhs) { return !(lhs == rhs); } @@ -983,7 +2014,16 @@ namespace etl /// Less than operator. cppreference 23 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator <(const etl::optional& lhs, const U& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator <(const etl::optional& lhs, const U& rhs) + { + return lhs.has_value() ? lhs.value() < rhs : true; + } + + //*************************************************************************** + /// Less than operator. cppreference 23 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator <(const etl::optional& lhs, const U& rhs) { return lhs.has_value() ? lhs.value() < rhs : true; } @@ -992,7 +2032,16 @@ namespace etl /// Less than operator. cppreference 24 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator <(const U& lhs, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator <(const U& lhs, const etl::optional& rhs) + { + return rhs.has_value() ? lhs < rhs.value() : false; + } + + //*************************************************************************** + /// Less than operator. cppreference 24 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator <(const U& lhs, const etl::optional& rhs) { return rhs.has_value() ? lhs < rhs.value() : false; } @@ -1001,7 +2050,16 @@ namespace etl /// Less than equal operator. cppreference 25 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator <=(const etl::optional& lhs, const U& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator <=(const etl::optional& lhs, const U& rhs) + { + return lhs.has_value() ? lhs.value() <= rhs : true; + } + + //*************************************************************************** + /// Less than equal operator. cppreference 25 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator <=(const etl::optional& lhs, const U& rhs) { return lhs.has_value() ? lhs.value() <= rhs : true; } @@ -1010,7 +2068,16 @@ namespace etl /// Less than equal operator. cppreference 26 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator <=(const U& lhs, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator <=(const U& lhs, const etl::optional& rhs) + { + return rhs.has_value() ? lhs <= rhs.value() : false; + } + + //*************************************************************************** + /// Less than equal operator. cppreference 26 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator <=(const U& lhs, const etl::optional& rhs) { return rhs.has_value() ? lhs <= rhs.value() : false; } @@ -1019,7 +2086,16 @@ namespace etl /// Greater than operator. cppreference 27 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator >(const etl::optional& lhs, const U& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator >(const etl::optional& lhs, const U& rhs) + { + return lhs.has_value() ? lhs.value() > rhs : false; + } + + //*************************************************************************** + /// Greater than operator. cppreference 27 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator >(const etl::optional& lhs, const U& rhs) { return lhs.has_value() ? lhs.value() > rhs : false; } @@ -1028,7 +2104,16 @@ namespace etl /// Greater than operator. cppreference 28 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator >(const U& lhs, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator >(const U& lhs, const etl::optional& rhs) + { + return rhs.has_value() ? lhs > rhs.value() : true; + } + + //*************************************************************************** + /// Greater than operator. cppreference 28 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator >(const U& lhs, const etl::optional& rhs) { return rhs.has_value() ? lhs > rhs.value() : true; } @@ -1037,7 +2122,16 @@ namespace etl /// Greater than equal operator. cppreference 29 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator >=(const etl::optional& lhs, const U& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator >=(const etl::optional& lhs, const U& rhs) + { + return lhs.has_value() ? lhs.value() >= rhs : false; + } + + //*************************************************************************** + /// Greater than equal operator. cppreference 29 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator >=(const etl::optional& lhs, const U& rhs) { return lhs.has_value() ? lhs.value() >= rhs : false; } @@ -1046,7 +2140,16 @@ namespace etl /// Greater than equal operator. cppreference 30 //*************************************************************************** template - ETL_CONSTEXPR20_STL bool operator >=(const U& lhs, const etl::optional& rhs) + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP14 operator >=(const U& lhs, const etl::optional& rhs) + { + return rhs.has_value() ? lhs >= rhs.value() : true; + } + + //*************************************************************************** + /// Greater than equal operator. cppreference 30 + //*************************************************************************** + template + ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL operator >=(const U& lhs, const etl::optional& rhs) { return rhs.has_value() ? lhs >= rhs.value() : true; } @@ -1080,4 +2183,10 @@ ETL_CONSTEXPR20_STL void swap(etl::optional& lhs, etl::optional& rhs) lhs.swap(rhs); } +#undef ETL_OPTIONAL_ENABLE_CPP14 +#undef ETL_OPTIONAL_ENABLE_CPP20_STL + +#undef ETL_OPTIONAL_ENABLE_CONSTEXPR_BOOL_RETURN_CPP20_STL +#undef ETL_OPTIONAL_ENABLE_COMSTEXPR_BOOL_RETURN_CPP20_STL + #endif diff --git a/test/test_optional.cpp b/test/test_optional.cpp index a6bbc650..f9ffdba7 100644 --- a/test/test_optional.cpp +++ b/test/test_optional.cpp @@ -53,6 +53,41 @@ std::ostream& operator << (std::ostream& os, const etl::optional& data) namespace { + //************************************************************************* + struct NonTrivial + { + constexpr NonTrivial() : a(0) {} + + constexpr NonTrivial(int a_) : a(a_) {} + + constexpr friend bool operator <(const NonTrivial& lhs, const NonTrivial& rhs) + { + return lhs.a < rhs.a; + } + + constexpr friend bool operator <=(const NonTrivial& lhs, const NonTrivial& rhs) + { + return lhs.a <= rhs.a; + } + + constexpr friend bool operator >(const NonTrivial& lhs, const NonTrivial& rhs) + { + return lhs.a > rhs.a; + } + + constexpr friend bool operator >=(const NonTrivial& lhs, const NonTrivial& rhs) + { + return lhs.a >= rhs.a; + } + + constexpr friend bool operator ==(const NonTrivial& lhs, const NonTrivial& rhs) + { + return lhs.a == rhs.a; + } + + int a; + }; + SUITE(test_optional) { //************************************************************************* @@ -153,10 +188,19 @@ namespace #include "etl/private/diagnostic_pop.h" } + //************************************************************************* + TEST(test_nullopt_pod) + { + etl::optional data(etl::nullopt); + data = 1; + data = etl::nullopt; + CHECK(!bool(data)); + } + //************************************************************************* TEST(test_nullopt) { - etl::optional data; + etl::optional data(etl::nullopt); data = Data("Hello"); data = etl::nullopt; CHECK(!bool(data)); @@ -239,6 +283,40 @@ namespace CHECK(!(Data("Data2") == data1)); } +#if ETL_USING_CPP20 && ETL_USING_STL + //************************************************************************* + TEST(test_constexpr_equality_non_trivial) + { + constexpr etl::optional data1(1); + constexpr etl::optional data2(2); + + constexpr bool eq1 = (data1 == data2); + constexpr bool eq2 = (data1 == etl::nullopt); + constexpr bool eq3 = (etl::nullopt == data1); + + CHECK(eq1); + CHECK(eq2); + CHECK(eq3); + } +#endif + +#if ETL_USING_CPP14 + //************************************************************************* + TEST(test_constexpr_equality_trivial) + { + constexpr etl::optional data1(1); + constexpr etl::optional data2(2); + + constexpr bool eq1 = (data1 == data2); + constexpr bool eq2 = (data1 == etl::nullopt); + constexpr bool eq3 = (etl::nullopt == data1); + + CHECK(eq1); + CHECK(eq2); + CHECK(eq3); + } +#endif + //************************************************************************* TEST(test_inequality) { @@ -276,6 +354,40 @@ namespace CHECK(Data("Data2") != data1); } +#if ETL_USING_CPP20 && ETL_USING_STL + //************************************************************************* + TEST(test_constexpr_inequality_non_trivial) + { + constexpr etl::optional data1(1); + constexpr etl::optional data2(2); + + constexpr bool eq1 = (data1 == data2); + constexpr bool eq2 = (data1 == etl::nullopt); + constexpr bool eq3 = (etl::nullopt == data1); + + CHECK(eq1); + CHECK(eq2); + CHECK(eq3); + } +#endif + +#if ETL_USING_CPP14 + //************************************************************************* + TEST(test_constexpr_inequality_trivial) + { + constexpr etl::optional data1(1); + constexpr etl::optional data2(2); + + constexpr bool neq1 = (data1 != data2); + constexpr bool neq2 = (data1 != etl::nullopt); + constexpr bool neq3 = (etl::nullopt != data1); + + CHECK(neq1); + CHECK(neq2); + CHECK(neq3); + } +#endif + //************************************************************************* #include "etl/private/diagnostic_uninitialized_push.h" TEST(test_less_than) @@ -310,6 +422,41 @@ namespace } #include "etl/private/diagnostic_pop.h" + +#if ETL_USING_CPP20 && ETL_USING_STL + //************************************************************************* + TEST(test_constexpr_less_than_non_trivial) + { + constexpr etl::optional data1(1); + constexpr etl::optional data2(2); + + constexpr bool lt1 = (data1 < data2); + constexpr bool lt2 = (data1 < etl::nullopt); + constexpr bool lt3 = (etl::nullopt < data1); + + CHECK(lt1); + CHECK(lt2); + CHECK(lt3); + } +#endif + +#if ETL_USING_CPP14 + //************************************************************************* + TEST(test_constexpr_less_than_trivial) + { + constexpr etl::optional data1(1); + constexpr etl::optional data2(2); + + constexpr bool lt1 = (data1 < data2); + constexpr bool lt2 = (data1 < etl::nullopt); + constexpr bool lt3 = (etl::nullopt < data1); + + CHECK(lt1); + CHECK(lt2); + CHECK(lt3); + } +#endif + //************************************************************************* TEST(test_less_than_equal) { @@ -344,6 +491,40 @@ namespace CHECK(Data("Data1") <= data1); } +#if ETL_USING_CPP20 && ETL_USING_STL + //************************************************************************* + TEST(test_constexpr_less_than_equal_non_trivial) + { + constexpr etl::optional data1(1); + constexpr etl::optional data2(2); + + constexpr bool lteq1 = (data1 <= data2); + constexpr bool lteq2 = (data1 <= etl::nullopt); + constexpr bool lteq3 = (etl::nullopt <= data1); + + CHECK(lteq1); + CHECK(lteq2); + CHECK(lteq3); + } +#endif + +#if ETL_USING_CPP14 + //************************************************************************* + TEST(test_constexpr_less_than_equal_trivial) + { + constexpr etl::optional data1(1); + constexpr etl::optional data2(2); + + constexpr bool lteq1 = (data1 <= data2); + constexpr bool lteq2 = (data1 <= etl::nullopt); + constexpr bool lteq3 = (etl::nullopt <= data1); + + CHECK(lteq1); + CHECK(lteq2); + CHECK(lteq3); + } +#endif + //************************************************************************* TEST(test_greater_than) { @@ -376,6 +557,40 @@ namespace CHECK(!(Data("Data1") > data2)); } +#if ETL_USING_CPP20 && ETL_USING_STL + //************************************************************************* + TEST(test_constexpr_greater_than_non_trivial) + { + constexpr etl::optional data1(1); + constexpr etl::optional data2(2); + + constexpr bool gteq1 = (data1 > data2); + constexpr bool gteq2 = (data1 > etl::nullopt); + constexpr bool gteq3 = (etl::nullopt > data1); + + CHECK(gteq1); + CHECK(gteq2); + CHECK(gteq3); + } +#endif + +#if ETL_USING_CPP14 + //************************************************************************* + TEST(test_constexpr_greater_than_trivial) + { + constexpr etl::optional data1(1); + constexpr etl::optional data2(2); + + constexpr bool gteq1 = (data1 > data2); + constexpr bool gteq2 = (data1 > etl::nullopt); + constexpr bool gteq3 = (etl::nullopt > data1); + + CHECK(gteq1); + CHECK(gteq2); + CHECK(gteq3); + } +#endif + //************************************************************************* TEST(test_greater_than_equal) { @@ -410,6 +625,40 @@ namespace CHECK(Data("Data1") >= data1); } +#if ETL_USING_CPP20 && ETL_USING_STL + //************************************************************************* + TEST(test_constexpr_greater_than_equal_non_trivial) + { + constexpr etl::optional data1(1); + constexpr etl::optional data2(2); + + constexpr bool gteq1 = (data1 >= data2); + constexpr bool gteq2 = (data1 >= etl::nullopt); + constexpr bool gteq3 = (etl::nullopt >= data1); + + CHECK(gteq1); + CHECK(gteq2); + CHECK(gteq3); + } +#endif + +#if ETL_USING_CPP14 + //************************************************************************* + TEST(test_constexpr_greater_than_equal_trivial) + { + constexpr etl::optional data1(1); + constexpr etl::optional data2(2); + + constexpr bool gteq1 = (data1 >= data2); + constexpr bool gteq2 = (data1 >= etl::nullopt); + constexpr bool gteq3 = (etl::nullopt >= data1); + + CHECK(gteq1); + CHECK(gteq2); + CHECK(gteq3); + } +#endif + //************************************************************************* TEST(test_container_of_optional) { From ea74d2f02f32452c059109fbbab56953fbf2f3e4 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 15 Feb 2024 10:50:45 +0000 Subject: [PATCH 5/5] etl::optional C++ compatibility updates --- include/etl/optional.h | 22 ++--- test/test_optional.cpp | 155 ++++++++++++++++---------------- test/vs2022/etl.vcxproj.filters | 30 +++++-- 3 files changed, 114 insertions(+), 93 deletions(-) diff --git a/include/etl/optional.h b/include/etl/optional.h index 7b55695f..c9901e13 100644 --- a/include/etl/optional.h +++ b/include/etl/optional.h @@ -138,7 +138,7 @@ namespace etl /// Copy constructor. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl(const optional_impl& other) + optional_impl(const optional_impl& other) { if (other.has_value()) { @@ -152,7 +152,7 @@ namespace etl /// Move constructor. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl(optional_impl&& other) + optional_impl(optional_impl&& other) { if (other.has_value()) { @@ -208,7 +208,7 @@ namespace etl /// Assignment operator from optional_impl. //*************************************************************************** ETL_CONSTEXPR20_STL - optional_impl& operator =(const optional_impl& other) + optional_impl& operator =(const optional_impl& other) { if (this != &other) { @@ -711,7 +711,7 @@ namespace etl /// Copy constructor. //*************************************************************************** ETL_CONSTEXPR14 - optional_impl(const optional_impl& other) + optional_impl(const optional_impl& other) { if (other.has_value()) { @@ -772,7 +772,7 @@ namespace etl /// Assignment operator from optional_impl. //*************************************************************************** ETL_CONSTEXPR14 - optional_impl& operator =(const optional_impl& other) + optional_impl& operator =(const optional_impl& other) { if (this != &other) { @@ -1277,7 +1277,7 @@ namespace etl template ETL_CONSTEXPR14 optional(etl::nullopt_t) - : impl_t(etl::nullopt_t{}) + : impl_t(etl::nullopt) { } @@ -1287,7 +1287,7 @@ namespace etl template ETL_CONSTEXPR20_STL optional(etl::nullopt_t) - : impl_t(etl::nullopt_t{}) + : impl_t(etl::nullopt) { } #else @@ -1295,7 +1295,7 @@ namespace etl /// Constructor with nullopt. //*************************************************************************** optional(etl::nullopt_t) - : impl_t(etl::nullopt_t{}) + : impl_t(etl::nullopt) { } #endif @@ -1415,7 +1415,7 @@ namespace etl ETL_CONSTEXPR14 optional& operator =(etl::nullopt_t) { - impl_t::operator=(etl::nullopt_t{}); + impl_t::operator=(etl::nullopt); return *this; } @@ -1427,7 +1427,7 @@ namespace etl ETL_CONSTEXPR20_STL optional& operator =(etl::nullopt_t) { - impl_t::operator=(etl::nullopt_t{}); + impl_t::operator=(etl::nullopt); return *this; } @@ -1437,7 +1437,7 @@ namespace etl //*************************************************************************** optional& operator =(etl::nullopt_t) { - impl_t::operator=(etl::nullopt_t{}); + impl_t::operator=(etl::nullopt); return *this; } diff --git a/test/test_optional.cpp b/test/test_optional.cpp index f9ffdba7..61e68672 100644 --- a/test/test_optional.cpp +++ b/test/test_optional.cpp @@ -53,6 +53,7 @@ std::ostream& operator << (std::ostream& os, const etl::optional& data) namespace { +#include "etl/private/diagnostic_unused_function_push.h" //************************************************************************* struct NonTrivial { @@ -65,21 +66,6 @@ namespace return lhs.a < rhs.a; } - constexpr friend bool operator <=(const NonTrivial& lhs, const NonTrivial& rhs) - { - return lhs.a <= rhs.a; - } - - constexpr friend bool operator >(const NonTrivial& lhs, const NonTrivial& rhs) - { - return lhs.a > rhs.a; - } - - constexpr friend bool operator >=(const NonTrivial& lhs, const NonTrivial& rhs) - { - return lhs.a >= rhs.a; - } - constexpr friend bool operator ==(const NonTrivial& lhs, const NonTrivial& rhs) { return lhs.a == rhs.a; @@ -87,6 +73,7 @@ namespace int a; }; +#include "etl/private/diagnostic_pop.h" SUITE(test_optional) { @@ -294,9 +281,9 @@ namespace constexpr bool eq2 = (data1 == etl::nullopt); constexpr bool eq3 = (etl::nullopt == data1); - CHECK(eq1); - CHECK(eq2); - CHECK(eq3); + CHECK_FALSE(eq1); + CHECK_FALSE(eq2); + CHECK_FALSE(eq3); } #endif @@ -311,9 +298,9 @@ namespace constexpr bool eq2 = (data1 == etl::nullopt); constexpr bool eq3 = (etl::nullopt == data1); - CHECK(eq1); - CHECK(eq2); - CHECK(eq3); + CHECK_FALSE(eq1); + CHECK_FALSE(eq2); + CHECK_FALSE(eq3); } #endif @@ -361,13 +348,13 @@ namespace constexpr etl::optional data1(1); constexpr etl::optional data2(2); - constexpr bool eq1 = (data1 == data2); - constexpr bool eq2 = (data1 == etl::nullopt); - constexpr bool eq3 = (etl::nullopt == data1); + constexpr bool eq1 = (data1 != data2); + constexpr bool eq2 = (data1 != etl::nullopt); + constexpr bool eq3 = (etl::nullopt != data1); - CHECK(eq1); - CHECK(eq2); - CHECK(eq3); + CHECK_TRUE(eq1); + CHECK_TRUE(eq2); + CHECK_TRUE(eq3); } #endif @@ -382,9 +369,9 @@ namespace constexpr bool neq2 = (data1 != etl::nullopt); constexpr bool neq3 = (etl::nullopt != data1); - CHECK(neq1); - CHECK(neq2); - CHECK(neq3); + CHECK_TRUE(neq1); + CHECK_TRUE(neq2); + CHECK_TRUE(neq3); } #endif @@ -431,12 +418,14 @@ namespace constexpr etl::optional data2(2); constexpr bool lt1 = (data1 < data2); - constexpr bool lt2 = (data1 < etl::nullopt); - constexpr bool lt3 = (etl::nullopt < data1); + constexpr bool lt2 = (data2 < data1); + constexpr bool lt3 = (data1 < etl::nullopt); + constexpr bool lt4 = (etl::nullopt < data1); - CHECK(lt1); - CHECK(lt2); - CHECK(lt3); + CHECK_TRUE(lt1); + CHECK_FALSE(lt2); + CHECK_FALSE(lt3); + CHECK_TRUE(lt4); } #endif @@ -448,12 +437,14 @@ namespace constexpr etl::optional data2(2); constexpr bool lt1 = (data1 < data2); - constexpr bool lt2 = (data1 < etl::nullopt); - constexpr bool lt3 = (etl::nullopt < data1); + constexpr bool lt2 = (data2 < data1); + constexpr bool lt3 = (data1 < etl::nullopt); + constexpr bool lt4 = (etl::nullopt < data1); - CHECK(lt1); - CHECK(lt2); - CHECK(lt3); + CHECK_TRUE(lt1); + CHECK_FALSE(lt2); + CHECK_FALSE(lt3); + CHECK_TRUE(lt4); } #endif @@ -498,13 +489,15 @@ namespace constexpr etl::optional data1(1); constexpr etl::optional data2(2); - constexpr bool lteq1 = (data1 <= data2); - constexpr bool lteq2 = (data1 <= etl::nullopt); - constexpr bool lteq3 = (etl::nullopt <= data1); + constexpr bool lt1 = (data1 <= data2); + constexpr bool lt2 = (data2 <= data1); + constexpr bool lt3 = (data1 <= etl::nullopt); + constexpr bool lt4 = (etl::nullopt <= data1); - CHECK(lteq1); - CHECK(lteq2); - CHECK(lteq3); + CHECK_TRUE(lt1); + CHECK_FALSE(lt2); + CHECK_FALSE(lt3); + CHECK_TRUE(lt4); } #endif @@ -515,13 +508,15 @@ namespace constexpr etl::optional data1(1); constexpr etl::optional data2(2); - constexpr bool lteq1 = (data1 <= data2); - constexpr bool lteq2 = (data1 <= etl::nullopt); - constexpr bool lteq3 = (etl::nullopt <= data1); + constexpr bool lt1 = (data1 <= data2); + constexpr bool lt2 = (data2 <= data1); + constexpr bool lt3 = (data1 <= etl::nullopt); + constexpr bool lt4 = (etl::nullopt <= data1); - CHECK(lteq1); - CHECK(lteq2); - CHECK(lteq3); + CHECK_TRUE(lt1); + CHECK_FALSE(lt2); + CHECK_FALSE(lt3); + CHECK_TRUE(lt4); } #endif @@ -564,13 +559,15 @@ namespace constexpr etl::optional data1(1); constexpr etl::optional data2(2); - constexpr bool gteq1 = (data1 > data2); - constexpr bool gteq2 = (data1 > etl::nullopt); - constexpr bool gteq3 = (etl::nullopt > data1); + constexpr bool gt1 = (data1 > data2); + constexpr bool gt2 = (data2 > data1); + constexpr bool gt3 = (data1 > etl::nullopt); + constexpr bool gt4 = (etl::nullopt > data1); - CHECK(gteq1); - CHECK(gteq2); - CHECK(gteq3); + CHECK_FALSE(gt1); + CHECK_TRUE(gt2); + CHECK_TRUE(gt3); + CHECK_FALSE(gt4); } #endif @@ -581,13 +578,15 @@ namespace constexpr etl::optional data1(1); constexpr etl::optional data2(2); - constexpr bool gteq1 = (data1 > data2); - constexpr bool gteq2 = (data1 > etl::nullopt); - constexpr bool gteq3 = (etl::nullopt > data1); + constexpr bool gt1 = (data1 > data2); + constexpr bool gt2 = (data2 > data1); + constexpr bool gt3 = (data1 > etl::nullopt); + constexpr bool gt4 = (etl::nullopt > data1); - CHECK(gteq1); - CHECK(gteq2); - CHECK(gteq3); + CHECK_FALSE(gt1); + CHECK_TRUE(gt2); + CHECK_TRUE(gt3); + CHECK_FALSE(gt4); } #endif @@ -632,13 +631,15 @@ namespace constexpr etl::optional data1(1); constexpr etl::optional data2(2); - constexpr bool gteq1 = (data1 >= data2); - constexpr bool gteq2 = (data1 >= etl::nullopt); - constexpr bool gteq3 = (etl::nullopt >= data1); + constexpr bool gte1 = (data1 >= data2); + constexpr bool gte2 = (data2 >= data1); + constexpr bool gte3 = (data1 >= etl::nullopt); + constexpr bool gte4 = (etl::nullopt >= data1); - CHECK(gteq1); - CHECK(gteq2); - CHECK(gteq3); + CHECK_FALSE(gte1); + CHECK_TRUE(gte2); + CHECK_TRUE(gte3); + CHECK_FALSE(gte4); } #endif @@ -649,13 +650,15 @@ namespace constexpr etl::optional data1(1); constexpr etl::optional data2(2); - constexpr bool gteq1 = (data1 >= data2); - constexpr bool gteq2 = (data1 >= etl::nullopt); - constexpr bool gteq3 = (etl::nullopt >= data1); + constexpr bool gte1 = (data1 >= data2); + constexpr bool gte2 = (data2 >= data1); + constexpr bool gte3 = (data1 >= etl::nullopt); + constexpr bool gte4 = (etl::nullopt >= data1); - CHECK(gteq1); - CHECK(gteq2); - CHECK(gteq3); + CHECK_FALSE(gte1); + CHECK_TRUE(gte2); + CHECK_TRUE(gte3); + CHECK_FALSE(gte4); } #endif diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index 2adfa862..5c457a21 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -3340,12 +3340,6 @@ Resource Files\CI\Appveyor - - Resource Files\CI\Github - - - Resource Files\CI\Github - Resource Files @@ -3412,6 +3406,30 @@ Tests\Scripts + + Resource Files\CI\Github + + + Resource Files\CI\Github + + + Resource Files\CI\Github + + + Resource Files\CI\Github + + + Resource Files\CI\Github + + + Resource Files\CI\Github + + + Resource Files\CI\Github + + + Resource Files\CI\Github +