diff --git a/include/nfx/detail/string/StringBuilder.inl b/include/nfx/detail/string/StringBuilder.inl index 74db4dc..cc6b828 100644 --- a/include/nfx/detail/string/StringBuilder.inl +++ b/include/nfx/detail/string/StringBuilder.inl @@ -33,6 +33,11 @@ #include #include +#if !NFX_STRINGBUILDER_HAS_FLOAT_TO_CHARS +# include +# include +#endif + namespace nfx::string { //===================================================================== @@ -298,11 +303,21 @@ namespace nfx::string { ensureCapacity( m_size + FLOAT_MAX_CHARS ); } +#if NFX_STRINGBUILDER_HAS_FLOAT_TO_CHARS auto [ptr, ec] = std::to_chars( m_buffer + m_size, m_buffer + m_capacity, value ); if( ec == std::errc() ) NFX_STRINGBUILDER_LIKELY { m_size = ptr - m_buffer; } +#else + char scratch[FLOAT_MAX_CHARS + 1]; + const int written = std::snprintf( scratch, sizeof( scratch ), "%.*g", + std::numeric_limits::max_digits10, static_cast( value ) ); + if( written > 0 ) + { + return append( std::string_view{ scratch, static_cast( written ) } ); + } +#endif return *this; } @@ -312,11 +327,21 @@ namespace nfx::string { ensureCapacity( m_size + DOUBLE_MAX_CHARS ); } +#if NFX_STRINGBUILDER_HAS_FLOAT_TO_CHARS auto [ptr, ec] = std::to_chars( m_buffer + m_size, m_buffer + m_capacity, value ); if( ec == std::errc() ) NFX_STRINGBUILDER_LIKELY { m_size = ptr - m_buffer; } +#else + char scratch[DOUBLE_MAX_CHARS + 1]; + const int written = std::snprintf( scratch, sizeof( scratch ), "%.*g", + std::numeric_limits::max_digits10, value ); + if( written > 0 ) + { + return append( std::string_view{ scratch, static_cast( written ) } ); + } +#endif return *this; } @@ -491,23 +516,43 @@ namespace nfx::string inline StringBuilder& StringBuilder::prepend( float value ) { +#if NFX_STRINGBUILDER_HAS_FLOAT_TO_CHARS char buffer[FLOAT_MAX_CHARS]; auto [ptr, ec] = std::to_chars( buffer, buffer + FLOAT_MAX_CHARS, value ); if( ec == std::errc() ) NFX_STRINGBUILDER_LIKELY { return prepend( std::string_view{ buffer, static_cast( ptr - buffer ) } ); } +#else + char buffer[FLOAT_MAX_CHARS + 1]; + const int written = std::snprintf( buffer, sizeof( buffer ), "%.*g", + std::numeric_limits::max_digits10, static_cast( value ) ); + if( written > 0 ) + { + return prepend( std::string_view{ buffer, static_cast( written ) } ); + } +#endif return *this; } inline StringBuilder& StringBuilder::prepend( double value ) { +#if NFX_STRINGBUILDER_HAS_FLOAT_TO_CHARS char buffer[DOUBLE_MAX_CHARS]; auto [ptr, ec] = std::to_chars( buffer, buffer + DOUBLE_MAX_CHARS, value ); if( ec == std::errc() ) NFX_STRINGBUILDER_LIKELY { return prepend( std::string_view{ buffer, static_cast( ptr - buffer ) } ); } +#else + char buffer[DOUBLE_MAX_CHARS + 1]; + const int written = std::snprintf( buffer, sizeof( buffer ), "%.*g", + std::numeric_limits::max_digits10, value ); + if( written > 0 ) + { + return prepend( std::string_view{ buffer, static_cast( written ) } ); + } +#endif return *this; } diff --git a/include/nfx/string/StringBuilder.h b/include/nfx/string/StringBuilder.h index 416d002..2169f6a 100644 --- a/include/nfx/string/StringBuilder.h +++ b/include/nfx/string/StringBuilder.h @@ -132,6 +132,22 @@ # define NFX_STRINGBUILDER_UNLIKELY #endif +/** + * @def NFX_STRINGBUILDER_HAS_FLOAT_TO_CHARS + * @brief Whether std::to_chars(float/double) is usable on this toolchain. + * @details Integer std::to_chars is universally available, but the + * floating-point overloads are not: IAR's libc++ ships them as deleted + * functions. When unavailable the float/double formatters fall back to + * std::snprintf. Define this to 0/1 before including to override. + */ +#if !defined( NFX_STRINGBUILDER_HAS_FLOAT_TO_CHARS ) +# if defined( __IAR_SYSTEMS_ICC__ ) +# define NFX_STRINGBUILDER_HAS_FLOAT_TO_CHARS 0 +# else +# define NFX_STRINGBUILDER_HAS_FLOAT_TO_CHARS 1 +# endif +#endif + namespace nfx::string { //=====================================================================