summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2024-12-29 11:09:16 +0100
committerCarl Hetherington <cth@carlh.net>2025-01-01 14:08:58 +0100
commit68533f20f9f2e0ca9efc9360f20d047a79e4fd8a (patch)
tree22ee64680ffb708f55d6fe4960f87efb0102c396 /src
parent23a542bd526038934e05a237d5434b9cd5beb855 (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.cc147
-rw-r--r--src/wscript7
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']