From 760ff8bd21bcaa0707eb6b75163f1ea7fdb64436 Mon Sep 17 00:00:00 2001 From: Michael Morgan Date: Sat, 20 May 2023 03:42:36 -0700 Subject: [PATCH] Add rvalue accessors to expected and optional, and update constructors. (#690) * Add rvalue methods to optional and expected. * Fix constructors in expected.h. * Fix sanity checks. --------- Co-authored-by: John Wellbelove --- include/etl/expected.h | 123 ++++++++++++++++----------- include/etl/optional.h | 184 ++++++++++++++++++++++++++++++----------- include/etl/platform.h | 30 ++++--- 3 files changed, 225 insertions(+), 112 deletions(-) diff --git a/include/etl/expected.h b/include/etl/expected.h index 4ac7259a..ff93fc7a 100644 --- a/include/etl/expected.h +++ b/include/etl/expected.h @@ -113,35 +113,28 @@ namespace etl } #endif -#if ETL_CPP11_SUPPORTED //******************************************* - /// Construct from argument. + /// Construct from an lvalue. //******************************************* - template ::type, unexpected>::value && - !etl::is_same::type, etl::in_place_t>::value, int>::type> - constexpr explicit unexpected(TErr&& e) - : error_value(etl::forward(e)) - { - } - -#else - //******************************************* - /// Construct from argument. - //******************************************* - template - explicit unexpected(const TErr& e, typename etl::enable_if::type, unexpected>::value && - !etl::is_same::type, etl::in_place_t>::value, int>::type = 0) + ETL_CONSTEXPR explicit unexpected(const TError& e) : error_value(e) { } -#endif #if ETL_USING_CPP11 + //******************************************* + /// Construct from an rvalue. + //******************************************* + ETL_CONSTEXPR explicit unexpected(TError&& e) + : error_value(etl::forward(e)) + { + } + //******************************************* /// Construct from arguments. //******************************************* template - constexpr explicit unexpected(etl::in_place_t, Args&&... args) + ETL_CONSTEXPR explicit unexpected(etl::in_place_t, Args&&... args) : error_value(etl::forward(args)...) { } @@ -152,7 +145,7 @@ namespace etl /// Construct from initializer_list and arguments. //******************************************* template - constexpr explicit unexpected(etl::in_place_t, std::initializer_list init, Args&&... args) + ETL_CONSTEXPR explicit unexpected(etl::in_place_t, std::initializer_list init, Args&&... args) : error_value(init, etl::forward(args)...) { } @@ -188,7 +181,7 @@ namespace etl //******************************************* /// Get the error. //******************************************* - TError& error() & noexcept + ETL_CONSTEXPR14 TError& error()& ETL_NOEXCEPT { return error_value; } @@ -196,15 +189,15 @@ namespace etl //******************************************* /// Get the error. //******************************************* - constexpr const TError& error() const& noexcept + ETL_CONSTEXPR14 const TError& error() const& ETL_NOEXCEPT { return error_value; } //******************************************* /// Get the error. - //******************************************* - TError&& error() && noexcept + //******************************************* + ETL_CONSTEXPR14 TError&& error()&& ETL_NOEXCEPT { return etl::move(error_value); } @@ -212,7 +205,7 @@ namespace etl //******************************************* /// Get the error. //******************************************* - constexpr TError&& error() const&& noexcept + ETL_CONSTEXPR14 TError&& error() const&& ETL_NOEXCEPT { return etl::move(error_value); } @@ -252,7 +245,7 @@ namespace etl }; #if ETL_USING_CPP17 - inline constexpr unexpect_t unexpect{}; + inline ETL_CONSTEXPR unexpect_t unexpect{}; #else static const unexpect_t unexpect; #endif @@ -322,8 +315,10 @@ namespace etl //******************************************* /// Copy construct from unexpected type. //******************************************* - template - ETL_CONSTEXPR14 explicit expected(const etl::unexpected& ue) + template + ETL_CONSTEXPR14 + ETL_EXPLICIT_EXPR(!etl::is_convertible_v) + expected(const etl::unexpected& ue) : storage(etl::in_place_index_t(), ue.error()) { } @@ -332,8 +327,10 @@ namespace etl //******************************************* /// Move construct from unexpected type. //******************************************* - template - ETL_CONSTEXPR14 explicit expected(etl::unexpected&& ue) + template + ETL_CONSTEXPR14 + ETL_EXPLICIT_EXPR(!etl::is_convertible_v) + expected(etl::unexpected&& ue) : storage(etl::in_place_index_t(), etl::move(ue.error())) { } @@ -388,7 +385,7 @@ namespace etl #endif //******************************************* - /// + /// //******************************************* this_type& operator =(const this_type& other) { @@ -401,7 +398,7 @@ namespace etl #if ETL_USING_CPP11 //******************************************* - /// + /// //******************************************* this_type& operator =(this_type&& other) { @@ -503,7 +500,7 @@ namespace etl #endif //******************************************* - /// + /// //******************************************* ETL_NODISCARD ETL_CONSTEXPR14 @@ -513,7 +510,7 @@ namespace etl } //******************************************* - /// + /// //******************************************* ETL_NODISCARD ETL_CONSTEXPR14 @@ -524,7 +521,7 @@ namespace etl #if ETL_USING_CPP11 //******************************************* - /// + /// //******************************************* template ETL_NODISCARD @@ -542,7 +539,7 @@ namespace etl } //******************************************* - /// + /// //******************************************* template ETL_NODISCARD @@ -560,7 +557,7 @@ namespace etl } //******************************************* - /// + /// //******************************************* ETL_NODISCARD ETL_CONSTEXPR14 @@ -570,7 +567,7 @@ namespace etl } //******************************************* - /// + /// //******************************************* ETL_NODISCARD ETL_CONSTEXPR14 @@ -580,17 +577,17 @@ namespace etl } //******************************************* - /// + /// //******************************************* ETL_NODISCARD ETL_CONSTEXPR14 - error_type&& error() && ETL_NOEXCEPT + error_type&& error()&& ETL_NOEXCEPT { return etl::move(etl::get(storage)); } //******************************************* - /// + /// //******************************************* ETL_NODISCARD ETL_CONSTEXPR14 @@ -600,7 +597,7 @@ namespace etl } //******************************************* - /// + /// //******************************************* template ETL_CONSTEXPR14 value_type& emplace(Args&&... args) ETL_NOEXCEPT @@ -609,7 +606,7 @@ namespace etl } //******************************************* - /// + /// //******************************************* template ETL_CONSTEXPR14 value_type& emplace(std::initializer_list& il, Args&&... args) ETL_NOEXCEPT @@ -618,7 +615,7 @@ namespace etl } #else //******************************************* - /// + /// //******************************************* template value_type value_or(const U& default_value) const @@ -634,7 +631,7 @@ namespace etl } //******************************************* - /// + /// //******************************************* error_type& error() const { @@ -643,7 +640,7 @@ namespace etl #endif //******************************************* - /// + /// //******************************************* value_type* operator ->() { @@ -655,7 +652,7 @@ namespace etl } //******************************************* - /// + /// //******************************************* const value_type* operator ->() const { @@ -667,9 +664,9 @@ namespace etl } //******************************************* - /// + /// //******************************************* - value_type& operator *() + value_type& operator *() ETL_LVALUE_REF_QUALIFIER { #if ETL_IS_DEBUG_BUILD ETL_ASSERT(storage.index() == Value_Type, ETL_ERROR(expected_invalid)); @@ -679,9 +676,9 @@ namespace etl } //******************************************* - /// + /// //******************************************* - const value_type& operator *() const + const value_type& operator *() const ETL_LVALUE_REF_QUALIFIER { #if ETL_IS_DEBUG_BUILD ETL_ASSERT(storage.index() == Value_Type, ETL_ERROR(expected_invalid)); @@ -690,6 +687,32 @@ namespace etl return etl::get(storage); } +#if ETL_USING_CPP11 + //******************************************* + /// + //******************************************* + value_type&& operator *()&& + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(storage.index() == Value_Type, ETL_ERROR(expected_invalid)); +#endif + + return etl::move(etl::get(storage)); + } + + //******************************************* + /// + //******************************************* + const value_type&& operator *() const&& + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(storage.index() == Value_Type, ETL_ERROR(expected_invalid)); +#endif + + return etl::move(etl::get(storage)); + } +#endif + private: enum diff --git a/include/etl/optional.h b/include/etl/optional.h index 875cda7b..b8a50355 100644 --- a/include/etl/optional.h +++ b/include/etl/optional.h @@ -302,7 +302,7 @@ namespace etl /// Dereference operator. //*************************************************************************** ETL_CONSTEXPR20_STL - T& operator *() + 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)); @@ -315,7 +315,7 @@ namespace etl /// Dereference operator. //*************************************************************************** ETL_CONSTEXPR20_STL - const T& operator *() const + 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)); @@ -324,6 +324,34 @@ namespace etl 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 //*************************************************************************** @@ -346,7 +374,7 @@ namespace etl /// Get a reference to the value. //*************************************************************************** ETL_CONSTEXPR20_STL - T& value() + T& value() ETL_LVALUE_REF_QUALIFIER { #if ETL_IS_DEBUG_BUILD ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); @@ -359,7 +387,7 @@ namespace etl /// Get a const reference to the value. //*************************************************************************** ETL_CONSTEXPR20_STL - const T& value() const + const T& value() const ETL_LVALUE_REF_QUALIFIER { #if ETL_IS_DEBUG_BUILD ETL_ASSERT(has_value(), ETL_ERROR(optional_invalid)); @@ -372,11 +400,48 @@ namespace etl /// Gets the value or a default if not valid. //*************************************************************************** ETL_CONSTEXPR20_STL - T value_or(T default_value) const + 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. + //*************************************************************************** + ETL_CONSTEXPR20_STL + T&& value_or(T&& default_value) const&& + { + return has_value() ? etl::move(value()) : default_value; + } +#endif + //*************************************************************************** /// Swaps this value with another. //*************************************************************************** @@ -739,7 +804,7 @@ namespace etl //*************************************************************************** /// Dereference operator. //*************************************************************************** - ETL_CONSTEXPR14 T& operator *() + ETL_CONSTEXPR14 T& operator *() ETL_LVALUE_REF_QUALIFIER { #if ETL_IS_DEBUG_BUILD ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); @@ -751,7 +816,7 @@ namespace etl //*************************************************************************** /// Dereference operator. //*************************************************************************** - ETL_CONSTEXPR14 const T& operator *() const + ETL_CONSTEXPR14 const T& operator *() const ETL_LVALUE_REF_QUALIFIER { #if ETL_IS_DEBUG_BUILD ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); @@ -760,6 +825,32 @@ namespace etl return storage; } +#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); + } + + //*************************************************************************** + /// 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); + } +#endif + //*************************************************************************** /// Bool conversion operator. //*************************************************************************** @@ -779,7 +870,7 @@ namespace etl //*************************************************************************** /// Get a reference to the value. //*************************************************************************** - ETL_CONSTEXPR14 T& value() + ETL_CONSTEXPR14 T& value() ETL_LVALUE_REF_QUALIFIER { #if ETL_IS_DEBUG_BUILD ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); @@ -791,7 +882,7 @@ namespace etl //*************************************************************************** /// Get a const reference to the value. //*************************************************************************** - ETL_CONSTEXPR14 const T& value() const + ETL_CONSTEXPR14 const T& value() const ETL_LVALUE_REF_QUALIFIER { #if ETL_IS_DEBUG_BUILD ETL_ASSERT(valid, ETL_ERROR(optional_invalid)); @@ -803,11 +894,45 @@ namespace etl //*************************************************************************** /// Gets the value or a default if no valid. //*************************************************************************** - ETL_CONSTEXPR14 T value_or(T default_value) const + 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); + } + + //*************************************************************************** + /// 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); + } + + //*************************************************************************** + /// Gets the value or a default if no valid. + //*************************************************************************** + ETL_CONSTEXPR14 T&& value_or(T&& default_value) const&& + { + return valid ? etl::move(value()) : default_value; + } +#endif + //*************************************************************************** /// Swaps this value with another. //*************************************************************************** @@ -947,19 +1072,6 @@ namespace etl ETL_CONSTEXPR14 bool operator <=(const etl::optional& lhs, const etl::optional& rhs) { return !(rhs < lhs); - - //if (!lhs.has_value()) - //{ - // return true; - //} - //else if (!rhs.has_value()) - //{ - // return false; - //} - //else - //{ - // return lhs.value() <= rhs.value(); - //} } //*************************************************************************** @@ -969,19 +1081,6 @@ namespace etl ETL_CONSTEXPR14 bool operator >(const etl::optional& lhs, const etl::optional& rhs) { return (rhs < lhs); - - //if (!lhs.has_value()) - //{ - // return false; - //} - //else if (!rhs.has_value()) - //{ - // return true; - //} - //else - //{ - // return lhs.value() > rhs.value(); - //} } //*************************************************************************** @@ -991,19 +1090,6 @@ namespace etl ETL_CONSTEXPR14 bool operator >=(const etl::optional& lhs, const etl::optional& rhs) { return !(lhs < rhs); - - //if (!rhs.has_value()) - //{ - // return true; - //} - //else if (!lhs.has_value()) - //{ - // return false; - //} - //else - //{ - // return lhs.value() >= rhs.value(); - //} } //*************************************************************************** diff --git a/include/etl/platform.h b/include/etl/platform.h index 19c78ae7..30d81a2d 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -70,7 +70,7 @@ SOFTWARE. //************************************* // Define debug macros. -#if (defined(_DEBUG) || defined(DEBUG)) && !defined(ETL_DEBUG) +#if (defined(_DEBUG) || defined(DEBUG)) && !defined(ETL_DEBUG) #define ETL_DEBUG #endif @@ -246,13 +246,14 @@ SOFTWARE. #define ETL_MOVE(x) etl::move(x) #define ETL_ENUM_CLASS(name) enum class name #define ETL_ENUM_CLASS_TYPE(name, type) enum class name : type + #define ETL_LVALUE_REF_QUALIFIER & #if ETL_USING_EXCEPTIONS - #define ETL_NOEXCEPT noexcept - #define ETL_NOEXCEPT_EXPR(expression) noexcept(expression) + #define ETL_NOEXCEPT noexcept + #define ETL_NOEXCEPT_EXPR(...) noexcept(__VA_ARGS__) #else #define ETL_NOEXCEPT - #define ETL_NOEXCEPT_EXPR(expression) + #define ETL_NOEXCEPT_EXPR(...) #endif #else #define ETL_CONSTEXPR @@ -264,10 +265,11 @@ SOFTWARE. #define ETL_FINAL #define ETL_NORETURN #define ETL_NOEXCEPT - #define ETL_NOEXCEPT_EXPR(expression) + #define ETL_NOEXCEPT_EXPR(...) #define ETL_MOVE(x) x #define ETL_ENUM_CLASS(name) enum name #define ETL_ENUM_CLASS_TYPE(name, type) enum name + #define ETL_LVALUE_REF_QUALIFIER #endif //************************************* @@ -303,12 +305,13 @@ SOFTWARE. //************************************* // C++20 #if ETL_USING_CPP20 && !defined(ETL_FORCE_NO_ADVANCED_CPP) - #define ETL_LIKELY [[likely]] - #define ETL_UNLIKELY [[unlikely]] - #define ETL_CONSTEXPR20 constexpr - #define ETL_CONSTEVAL consteval - #define ETL_CONSTINIT constinit - #define ETL_NO_UNIQUE_ADDRESS [[no_unique_address]] + #define ETL_LIKELY [[likely]] + #define ETL_UNLIKELY [[unlikely]] + #define ETL_CONSTEXPR20 constexpr + #define ETL_CONSTEVAL consteval + #define ETL_CONSTINIT constinit + #define ETL_NO_UNIQUE_ADDRESS [[no_unique_address]] + #define ETL_EXPLICIT_EXPR(...) explicit(__VA_ARGS__) #else #define ETL_LIKELY #define ETL_UNLIKELY @@ -316,6 +319,7 @@ SOFTWARE. #define ETL_CONSTEVAL #define ETL_CONSTINIT #define ETL_NO_UNIQUE_ADDRESS + #define ETL_EXPLICIT_EXPR(...) explicit #endif #if ETL_USING_CPP20 && ETL_USING_STL @@ -443,7 +447,7 @@ namespace etl static ETL_CONSTANT bool using_generic_compiler = (ETL_USING_GENERIC_COMPILER == 1); static ETL_CONSTANT bool using_legacy_bitset = (ETL_USING_LEGACY_BITSET == 1); static ETL_CONSTANT bool using_exceptions = (ETL_USING_EXCEPTIONS == 1); - + // Has... static ETL_CONSTANT bool has_initializer_list = (ETL_HAS_INITIALIZER_LIST == 1); static ETL_CONSTANT bool has_8bit_types = (ETL_USING_8BIT_TYPES == 1); @@ -464,7 +468,7 @@ namespace etl // Is... static ETL_CONSTANT bool is_debug_build = (ETL_IS_DEBUG_BUILD == 1); - + } }