From 2a79845dd5f78043135bbfec3bc09da781d8f636 Mon Sep 17 00:00:00 2001 From: Drew Rife Date: Fri, 6 Feb 2026 04:32:54 -0500 Subject: [PATCH] Add ref-qualifiers to basic_format_spec (#1292) * Remove AppVeyor build status badge Removed AppVeyor build status badge from README. * Update README.md * Update CONTRIBUTING.md Updated the instructions for contributing. * Fix for issue 1276 "Data corruption in the etl::bip_buffer_spsc_atomic" (#1277) * Reproduce data corruption bug in the `etl::bip_buffer_spsc_atomic`. * Fix data corruption bug in the `etl::bip_buffer_spsc_atomic`. * feat: use ref-qualifiers for basic_format_spec Converted the l-value methods to ref-qualified and also added r-value ref-qualified methods. --------- Co-authored-by: John Wellbelove Co-authored-by: Sergei --- include/etl/basic_format_spec.h | 177 ++++++++++++++++++++++++++------ include/etl/platform.h | 2 + test/test_format_spec.cpp | 87 ++++++++++++++++ 3 files changed, 232 insertions(+), 34 deletions(-) diff --git a/include/etl/basic_format_spec.h b/include/etl/basic_format_spec.h index 36c2d74c..c374e35f 100644 --- a/include/etl/basic_format_spec.h +++ b/include/etl/basic_format_spec.h @@ -36,6 +36,7 @@ SOFTWARE. #include "platform.h" #include "type_traits.h" #include "static_assert.h" +#include "utility.h" namespace etl { @@ -206,7 +207,7 @@ namespace etl //*************************************************************************** /// Default constructor. //*************************************************************************** - ETL_CONSTEXPR basic_format_spec() + ETL_CONSTEXPR basic_format_spec() ETL_NOEXCEPT : base_(10U) , width_(0U) , precision_(0U) @@ -228,7 +229,7 @@ namespace etl bool left_justified__, bool boolalpha__, bool show_base__, - typename TString::value_type fill__) + typename TString::value_type fill__) ETL_NOEXCEPT : base_(base__) , width_(width__) , precision_(precision__) @@ -243,7 +244,7 @@ namespace etl //*************************************************************************** /// Clears the format spec back to default. //*************************************************************************** - ETL_CONSTEXPR14 void clear() + ETL_CONSTEXPR14 void clear() ETL_NOEXCEPT { base_ = 10U; width_ = 0U; @@ -259,56 +260,93 @@ namespace etl /// Sets the base. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& base(uint32_t b) + ETL_CONSTEXPR14 basic_format_spec& base(uint32_t b) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { base_ = static_cast(b); return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& base(uint32_t b) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + base_ = static_cast(b); + return etl::move(*this); + } +#endif + //*************************************************************************** /// Sets the base to binary. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& binary() + ETL_CONSTEXPR14 basic_format_spec& binary() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { - base(2); - return *this; + return base(2); } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& binary() ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + return etl::move(base(2)); + } +#endif + //*************************************************************************** /// Sets the base to octal. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& octal() + ETL_CONSTEXPR14 basic_format_spec& octal() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { - base(8); - return *this; + return base(8); } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& octal() ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + return etl::move(base(8)); + } +#endif + //*************************************************************************** /// Sets the base to decimal. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& decimal() + ETL_CONSTEXPR14 basic_format_spec& decimal() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { - base(10); - return *this; + return base(10); } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& decimal() ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + return etl::move(base(10)); + } +#endif + //*************************************************************************** /// Sets the base to hex. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& hex() + ETL_CONSTEXPR14 basic_format_spec& hex() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { - base(16); - return *this; + return base(16); } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& hex() ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + return etl::move(base(16)); + } +#endif + //*************************************************************************** /// Gets the base. //*************************************************************************** - ETL_CONSTEXPR uint32_t get_base() const + ETL_CONSTEXPR uint32_t get_base() const ETL_NOEXCEPT { return base_; } @@ -317,16 +355,25 @@ namespace etl /// Sets the show base flag. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& show_base(bool b) + ETL_CONSTEXPR14 basic_format_spec& show_base(bool b) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { show_base_ = b; return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& show_base(bool b) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + show_base_ = b; + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the show base flag. //*************************************************************************** - ETL_CONSTEXPR bool is_show_base() const + ETL_CONSTEXPR bool is_show_base() const ETL_NOEXCEPT { return show_base_; } @@ -335,16 +382,25 @@ namespace etl /// Sets the width. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& width(uint32_t w) + ETL_CONSTEXPR14 basic_format_spec& width(uint32_t w) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { width_ = static_cast(w); return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& width(uint32_t w) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + width_ = static_cast(w); + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the width. //*************************************************************************** - ETL_CONSTEXPR uint32_t get_width() const + ETL_CONSTEXPR uint32_t get_width() const ETL_NOEXCEPT { return width_; } @@ -353,16 +409,25 @@ namespace etl /// Sets the precision. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& precision(uint32_t p) + ETL_CONSTEXPR14 basic_format_spec& precision(uint32_t p) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { precision_ = static_cast(p); return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& precision(uint32_t p) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + precision_ = static_cast(p); + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the precision. //*************************************************************************** - ETL_CONSTEXPR uint32_t get_precision() const + ETL_CONSTEXPR uint32_t get_precision() const ETL_NOEXCEPT { return precision_; } @@ -371,16 +436,25 @@ namespace etl /// Sets the upper case flag. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& upper_case(bool u) + ETL_CONSTEXPR14 basic_format_spec& upper_case(bool u) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { upper_case_ = u; return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& upper_case(bool u) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + upper_case_ = u; + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the upper case flag. //*************************************************************************** - ETL_CONSTEXPR bool is_upper_case() const + ETL_CONSTEXPR bool is_upper_case() const ETL_NOEXCEPT { return upper_case_; } @@ -389,16 +463,25 @@ namespace etl /// Sets the fill character. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& fill(typename TString::value_type c) + ETL_CONSTEXPR14 basic_format_spec& fill(typename TString::value_type c) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { fill_ = c; return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& fill(typename TString::value_type c) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + fill_ = c; + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the fill character. //*************************************************************************** - ETL_CONSTEXPR typename TString::value_type get_fill() const + ETL_CONSTEXPR typename TString::value_type get_fill() const ETL_NOEXCEPT { return fill_; } @@ -407,16 +490,25 @@ namespace etl /// Sets the left justify flag. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& left() + ETL_CONSTEXPR14 basic_format_spec& left() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { left_justified_ = true; return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& left() ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + left_justified_ = true; + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the left justify flag. //*************************************************************************** - ETL_CONSTEXPR bool is_left() const + ETL_CONSTEXPR bool is_left() const ETL_NOEXCEPT { return left_justified_; } @@ -425,16 +517,25 @@ namespace etl /// Sets the right justify flag. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& right() + ETL_CONSTEXPR14 basic_format_spec& right() ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { left_justified_ = false; return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& right() ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + left_justified_ = false; + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the right justify flag. //*************************************************************************** - ETL_CONSTEXPR bool is_right() const + ETL_CONSTEXPR bool is_right() const ETL_NOEXCEPT { return !left_justified_; } @@ -443,16 +544,25 @@ namespace etl /// Sets the bool alpha flag. /// \return A reference to the basic_format_spec. //*************************************************************************** - ETL_CONSTEXPR14 basic_format_spec& boolalpha(bool b) + ETL_CONSTEXPR14 basic_format_spec& boolalpha(bool b) ETL_LVALUE_REF_QUALIFIER ETL_NOEXCEPT { boolalpha_ = b; return *this; } +#if ETL_USING_CPP11 + /// @overload + ETL_CONSTEXPR14 basic_format_spec&& boolalpha(bool b) ETL_RVALUE_REF_QUALIFIER ETL_NOEXCEPT + { + boolalpha_ = b; + return etl::move(*this); + } +#endif + //*************************************************************************** /// Gets the boolalpha flag. //*************************************************************************** - ETL_CONSTEXPR bool is_boolalpha() const + ETL_CONSTEXPR bool is_boolalpha() const ETL_NOEXCEPT { return boolalpha_; } @@ -481,7 +591,6 @@ namespace etl } private: - uint_least8_t base_; uint_least8_t width_; uint_least8_t precision_; diff --git a/include/etl/platform.h b/include/etl/platform.h index 116daeb4..6db7c305 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -368,6 +368,7 @@ SOFTWARE. #define ETL_ENUM_CLASS(name) enum class name #define ETL_ENUM_CLASS_TYPE(name, type) enum class name : type #define ETL_LVALUE_REF_QUALIFIER & + #define ETL_RVALUE_REF_QUALIFIER && #if ETL_USING_EXCEPTIONS #define ETL_NOEXCEPT noexcept #define ETL_NOEXCEPT_EXPR(...) noexcept(__VA_ARGS__) @@ -393,6 +394,7 @@ SOFTWARE. #define ETL_ENUM_CLASS(name) enum name #define ETL_ENUM_CLASS_TYPE(name, type) enum name #define ETL_LVALUE_REF_QUALIFIER + #define ETL_RVALUE_REF_QUALIFIER #endif //************************************* diff --git a/test/test_format_spec.cpp b/test/test_format_spec.cpp index 57eb0841..d242dd79 100644 --- a/test/test_format_spec.cpp +++ b/test/test_format_spec.cpp @@ -91,6 +91,93 @@ namespace CHECK_EQUAL(true, format.is_upper_case()); } + //************************************************************************* +#if ETL_USING_CPP11 + TEST(test_format_rvalue_ref_qualifiers) + { + // Test chaining on temporary (rvalue) + auto format = etl::format_spec() + .base(16) + .boolalpha(true) + .fill('*') + .left() + .precision(3) + .show_base(true) + .upper_case(true) + .width(8); + + CHECK_EQUAL(16, format.get_base()); + CHECK_EQUAL('*', format.get_fill()); + CHECK_EQUAL(3, format.get_precision()); + CHECK_EQUAL(8, format.get_width()); + CHECK_EQUAL(true, format.is_boolalpha()); + CHECK_EQUAL(true, format.is_left()); + CHECK_EQUAL(false, format.is_right()); + CHECK_EQUAL(true, format.is_show_base()); + CHECK_EQUAL(true, format.is_upper_case()); + } + + //************************************************************************* + TEST(test_format_lvalue_ref_qualifiers) + { + // Test chaining on lvalue + etl::format_spec format; + + format.hex().boolalpha(true).fill('#').right().precision(5).show_base(false).upper_case(false).width(12); + + CHECK_EQUAL(16, format.get_base()); + CHECK_EQUAL('#', format.get_fill()); + CHECK_EQUAL(5, format.get_precision()); + CHECK_EQUAL(12, format.get_width()); + CHECK_EQUAL(true, format.is_boolalpha()); + CHECK_EQUAL(false, format.is_left()); + CHECK_EQUAL(true, format.is_right()); + CHECK_EQUAL(false, format.is_show_base()); + CHECK_EQUAL(false, format.is_upper_case()); + } + + //************************************************************************* + TEST(test_format_base_methods) + { + // Test binary + auto format_bin = etl::format_spec().binary().width(8).fill('0'); + CHECK_EQUAL(2, format_bin.get_base()); + CHECK_EQUAL(8, format_bin.get_width()); + CHECK_EQUAL('0', format_bin.get_fill()); + + // Test octal + auto format_oct = etl::format_spec().octal().width(6); + CHECK_EQUAL(8, format_oct.get_base()); + CHECK_EQUAL(6, format_oct.get_width()); + + // Test decimal + auto format_dec = etl::format_spec().decimal().precision(2); + CHECK_EQUAL(10, format_dec.get_base()); + CHECK_EQUAL(2, format_dec.get_precision()); + + // Test hex + auto format_hex = etl::format_spec().hex().upper_case(true); + CHECK_EQUAL(16, format_hex.get_base()); + CHECK_EQUAL(true, format_hex.is_upper_case()); + } + + //************************************************************************* + TEST(test_format_mixed_lvalue_rvalue) + { + // Create as rvalue, then use as lvalue + auto format = etl::format_spec().hex().width(8); + + // Continue chaining on lvalue + format.fill('0').upper_case(true).show_base(true); + + CHECK_EQUAL(16, format.get_base()); + CHECK_EQUAL('0', format.get_fill()); + CHECK_EQUAL(8, format.get_width()); + CHECK_EQUAL(true, format.is_upper_case()); + CHECK_EQUAL(true, format.is_show_base()); + } +#endif + //************************************************************************* #if ETL_USING_CPP14 TEST(test_format_constexpr)