diff options
| author | Carl Hetherington <cth@carlh.net> | 2024-12-29 11:09:16 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2025-01-01 14:08:58 +0100 |
| commit | 68533f20f9f2e0ca9efc9360f20d047a79e4fd8a (patch) | |
| tree | 22ee64680ffb708f55d6fe4960f87efb0102c396 /src | |
| parent | 23a542bd526038934e05a237d5434b9cd5beb855 (diff) | |
Add new, improved raw_convert using fmt/fast_float (DoM #2220).
The old one was broken if the thousands separator was the same
as the decimal separator (e.g. if you set de_DE and change the
decimal separator to .)
Diffstat (limited to 'src')
| -rw-r--r-- | src/raw_convert.cc | 147 | ||||
| -rw-r--r-- | src/wscript | 7 |
2 files changed, 86 insertions, 68 deletions
diff --git a/src/raw_convert.cc b/src/raw_convert.cc index c806b45e..eeab0dad 100644 --- a/src/raw_convert.cc +++ b/src/raw_convert.cc @@ -33,7 +33,8 @@ #include "raw_convert.h" -#include "locale_convert.h" +#include <fmt/format.h> +#include <fast_float/fast_float.h> #include <boost/algorithm/string.hpp> @@ -41,91 +42,79 @@ using std::string; using std::wstring; -/** @param v Numeric value as an ASCII string */ -static -string -make_raw (string v) -{ - struct lconv* lc = localeconv (); - /* thousands_sep may be . so remove them before changing decimal points */ - boost::algorithm::replace_all (v, lc->thousands_sep, ""); - boost::algorithm::replace_all (v, lc->decimal_point, "."); - return v; -} - - -static +template <> string -make_local (string v) +dcp::raw_convert(unsigned char v, int, bool) { - struct lconv* lc = localeconv (); - boost::algorithm::replace_all (v, ".", lc->decimal_point); - /* We hope it's ok not to add in thousands separators here */ - return v; + return fmt::to_string(v); } template <> string -dcp::raw_convert (unsigned char v, int precision, bool fixed) +dcp::raw_convert(unsigned short int v, int, bool) { - return make_raw (locale_convert<string> (v, precision, fixed)); + return fmt::to_string(v); } template <> string -dcp::raw_convert (unsigned short int v, int precision, bool fixed) +dcp::raw_convert(int v, int, bool) { - return make_raw (locale_convert<string> (v, precision, fixed)); + return fmt::to_string(v); } template <> string -dcp::raw_convert (int v, int precision, bool fixed) +dcp::raw_convert(unsigned int v, int, bool) { - return make_raw (locale_convert<string> (v, precision, fixed)); + return fmt::to_string(v); } template <> string -dcp::raw_convert (unsigned int v, int precision, bool fixed) +dcp::raw_convert(long v, int, bool) { - return make_raw (locale_convert<string> (v, precision, fixed)); + return fmt::to_string(v); } template <> string -dcp::raw_convert (long v, int precision, bool fixed) +dcp::raw_convert(unsigned long v, int, bool) { - return make_raw (locale_convert<string> (v, precision, fixed)); + return fmt::to_string(v); } template <> string -dcp::raw_convert (unsigned long v, int precision, bool fixed) +dcp::raw_convert(long long v, int, bool) { - return make_raw (locale_convert<string> (v, precision, fixed)); + return fmt::to_string(v); } template <> string -dcp::raw_convert (long long v, int precision, bool fixed) +dcp::raw_convert(unsigned long long v, int, bool) { - return make_raw (locale_convert<string> (v, precision, fixed)); + return fmt::to_string(v); } -template <> -string -dcp::raw_convert (unsigned long long v, int precision, bool fixed) +static +void +make_format_string(char* buffer, int buffer_length, int precision, bool fixed) { - return make_raw (locale_convert<string> (v, precision, fixed)); + if (fixed) { + snprintf(buffer, buffer_length, "{:.%df}", precision); + } else { + snprintf(buffer, buffer_length, "{:.%d}", precision); + } } @@ -133,7 +122,13 @@ template <> string dcp::raw_convert (float v, int precision, bool fixed) { - return make_raw (locale_convert<string> (v, precision, fixed)); + if (precision < 16) { + char format[16]; + make_format_string(format, 16, precision, fixed); + return fmt::format(format, v); + } + + return fmt::to_string(v); } @@ -141,7 +136,13 @@ template <> string dcp::raw_convert (double v, int precision, bool fixed) { - return make_raw (locale_convert<string> (v, precision, fixed)); + if (precision < 16) { + char format[16]; + make_format_string(format, 16, precision, fixed); + return fmt::format(format, v); + } + + return fmt::to_string(v); } @@ -188,105 +189,119 @@ dcp::raw_convert (wchar_t const * v, int, bool) } +template <typename T> +T +convert_with_fast_float(string v) +{ + T result; + auto const answer = fast_float::from_chars(v.data(), v.data() + v.size(), result); + if (answer.ec != std::errc()) { + return 0; + } + + return result; +} + + template <> unsigned char -dcp::raw_convert(string v, int precision, bool fixed) +dcp::raw_convert(string v, int, bool) { - return locale_convert<unsigned char> (make_local (v), precision, fixed); + return convert_with_fast_float<unsigned char>(v); } template <> unsigned short int -dcp::raw_convert(string v, int precision, bool fixed) +dcp::raw_convert(string v, int, bool) { - return locale_convert<unsigned short int> (make_local (v), precision, fixed); + return convert_with_fast_float<unsigned short int>(v); } template <> int -dcp::raw_convert (string v, int precision, bool fixed) +dcp::raw_convert(string v, int, bool) { - return locale_convert<int> (make_local (v), precision, fixed); + return convert_with_fast_float<int>(v); } template <> long -dcp::raw_convert (string v, int precision, bool fixed) +dcp::raw_convert(string v, int, bool) { - return locale_convert<long> (make_local (v), precision, fixed); + return convert_with_fast_float<long>(v); } template <> unsigned long -dcp::raw_convert (string v, int precision, bool fixed) +dcp::raw_convert(string v, int, bool) { - return locale_convert<unsigned long> (make_local (v), precision, fixed); + return convert_with_fast_float<unsigned long>(v); } template <> long long -dcp::raw_convert (string v, int precision, bool fixed) +dcp::raw_convert(string v, int, bool) { - return locale_convert<long long> (make_local (v), precision, fixed); + return convert_with_fast_float<long long>(v); } template <> unsigned long long -dcp::raw_convert (string v, int precision, bool fixed) +dcp::raw_convert(string v, int, bool) { - return locale_convert<unsigned long long> (make_local (v), precision, fixed); + return convert_with_fast_float<unsigned long long>(v); } template <> int -dcp::raw_convert(char* v, int precision, bool fixed) +dcp::raw_convert(char* v, int, bool) { - return locale_convert<int>(make_local (v), precision, fixed); + return convert_with_fast_float<int>(string(v)); } template <> int -dcp::raw_convert (char const * v, int precision, bool fixed) +dcp::raw_convert(char const * v, int, bool) { - return locale_convert<int> (make_local (v), precision, fixed); + return convert_with_fast_float<int>(string(v)); } template <> float -dcp::raw_convert (string v, int precision, bool fixed) +dcp::raw_convert(string v, int, bool) { - return locale_convert<float> (make_local (v), precision, fixed); + return convert_with_fast_float<float>(v); } template <> float -dcp::raw_convert (char const * v, int precision, bool fixed) +dcp::raw_convert(char const * v, int, bool) { - return locale_convert<float> (make_local (v), precision, fixed); + return convert_with_fast_float<float>(string(v)); } template <> double -dcp::raw_convert (string v, int precision, bool fixed) +dcp::raw_convert(string v, int, bool) { - return locale_convert<double> (make_local (v), precision, fixed); + return convert_with_fast_float<double>(v); } template <> double -dcp::raw_convert (char const * v, int precision, bool fixed) +dcp::raw_convert(char const * v, int, bool) { - return locale_convert<double> (make_local (v), precision, fixed); + return convert_with_fast_float<double>(string(v)); } diff --git a/src/wscript b/src/wscript index 1f0190fc..576ca748 100644 --- a/src/wscript +++ b/src/wscript @@ -252,6 +252,9 @@ def build(bld): warnings.h """ + + uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1 ASDCPLIB_DCPOMATIC XERCES AVCODEC AVUTIL FMT FAST_FLOAT' + # Main library if bld.env.STATIC: obj = bld(features='cxx cxxstlib') @@ -260,7 +263,7 @@ def build(bld): obj.name = 'libdcp%s' % bld.env.API_VERSION obj.target = 'dcp%s' % bld.env.API_VERSION obj.export_includes = ['.'] - obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1 ASDCPLIB_DCPOMATIC XERCES AVCODEC AVUTIL' + obj.uselib = uselib obj.source = source # Library for gcov @@ -272,7 +275,7 @@ def build(bld): obj.name = 'libdcp%s_gcov' % bld.env.API_VERSION obj.target = 'dcp%s_gcov' % bld.env.API_VERSION obj.export_includes = ['.'] - obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG CXML XMLSEC1 ASDCPLIB_DCPOMATIC XERCES AVCODEC AVUTIL' + obj.uselib = uselib obj.use = 'libkumu-libdcp%s libasdcp-libdcp%s' % (bld.env.API_VERSION, bld.env.API_VERSION) obj.source = source obj.cppflags = ['-fprofile-arcs', '-ftest-coverage', '-fno-inline', '-fno-default-inline', '-fno-elide-constructors', '-g', '-O0'] |
