From 3672482d9d1574f8102c52bfa7dc27c4c3051c55 Mon Sep 17 00:00:00 2001 From: Salvo Miosi Date: Sun, 4 Jul 2021 17:52:07 +0200 Subject: [PATCH] Adds custom boost::locale::numpunct --- include/boost/locale.hpp | 1 + include/boost/locale/numpunct.hpp | 102 ++++++++++++++++++++++++++++++ src/icu/numeric.cpp | 39 ++++++++++++ src/posix/numeric.cpp | 13 ++-- src/shared/ids.cpp | 6 ++ src/win32/numeric.cpp | 36 ++++------- 6 files changed, 164 insertions(+), 33 deletions(-) create mode 100644 include/boost/locale/numpunct.hpp diff --git a/include/boost/locale.hpp b/include/boost/locale.hpp index 989bba6c..0094827f 100644 --- a/include/boost/locale.hpp +++ b/include/boost/locale.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/locale/numpunct.hpp b/include/boost/locale/numpunct.hpp new file mode 100644 index 00000000..92fe3890 --- /dev/null +++ b/include/boost/locale/numpunct.hpp @@ -0,0 +1,102 @@ +// +// Copyright (c) 2021-2021 Salvo Miosi +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_LOCALE_NUMPUNCT_HPP_INCLUDED +#define BOOST_LOCALE_NUMPUNCT_HPP_INCLUDED +#include +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable : 4275 4251 4231 4660) +#endif +#include +#include + +namespace boost { + namespace locale { + + template + class BOOST_LOCALE_DECL numpunct_base : public std::locale::facet + { + typedef std::basic_string string_type; + public: + numpunct_base(size_t refs = 0) : std::locale::facet(refs) {} + + string_type decimal_point() const { + return do_decimal_point(); + } + + string_type thousands_sep() const { + return do_thousands_sep(); + } + + std::string grouping() const { + return do_grouping(); + } + + string_type truename() const { + return do_truename(); + } + + string_type falsename() const { + return do_falsename(); + } + + protected: + virtual string_type do_decimal_point() const { + static const char t[] = "."; + return string_type(t, t + sizeof(t) - 1); + } + virtual string_type do_thousands_sep() const { + static const char t[] = ","; + return string_type(t, t + sizeof(t) - 1); + } + virtual std::string do_grouping() const { + return ""; + } + virtual string_type do_truename() const { + static const char t[] = "true"; + return string_type(t, t + sizeof(t) - 1); + } + virtual string_type do_falsename() const { + static const char t[] = "false"; + return string_type(t, t + sizeof(t) - 1); + } + }; + + template struct numpunct {}; + + template<> struct numpunct : numpunct_base { + static std::locale::id id; + + numpunct (size_t refs = 0) : numpunct_base(refs) {} + }; + + template<> struct numpunct : numpunct_base { + static std::locale::id id; + + numpunct (size_t refs = 0) : numpunct_base(refs) {} + }; + + #ifdef BOOST_LOCALE_ENABLE_CHAR16_T + template<> struct numpunct : numpunct_base { + static std::locale::id id; + + numpunct (size_t refs = 0) : numpunct_base(refs) {} + }; + #endif + #ifdef BOOST_LOCALE_ENABLE_CHAR32_T + template<> struct numpunct : numpunct_base { + static std::locale::id id; + + numpunct (size_t refs = 0) : numpunct_base(refs) {} + }; + #endif + } +} + +#endif \ No newline at end of file diff --git a/src/icu/numeric.cpp b/src/icu/numeric.cpp index debecfb8..d2a28cca 100644 --- a/src/icu/numeric.cpp +++ b/src/icu/numeric.cpp @@ -13,10 +13,12 @@ #include "formatter.hpp" #include #include +#include #include "all_generator.hpp" #include "cdata.hpp" #include #include "predefined_formatters.hpp" +#include "uconv.hpp" namespace boost { namespace locale { @@ -354,6 +356,42 @@ class num_parse : public std::num_get, protected num_base }; +template +struct icu_numpunct : public numpunct { + typedef std::basic_string string_type; +public: + icu_numpunct(icu::Locale const &loc) + { + UErrorCode err; + icu::NumberFormat *fmt = icu::NumberFormat::createInstance(loc, UNUM_DECIMAL, err); + if (auto *dec = dynamic_cast(fmt)) { + boost::locale::impl_icu::icu_std_converter cnv("UTF-8"); + const icu::DecimalFormatSymbols *syms = dec->getDecimalFormatSymbols(); + decimal_point_ = cnv.std(syms->getSymbol(icu::DecimalFormatSymbols::kDecimalSeparatorSymbol)); + thousands_sep_ = cnv.std(syms->getSymbol(icu::DecimalFormatSymbols::kGroupingSeparatorSymbol)); + if (dec->isGroupingUsed()) { + char grouping_size = dec->getGroupingSize(); + grouping_ = std::string(&grouping_size, 1); + } + } + } +protected: + virtual string_type do_decimal_point() const { + return decimal_point_; + } + virtual string_type do_thousands_sep() const { + return thousands_sep_; + } + virtual std::string do_grouping() const { + return grouping_; + } + +private: + string_type decimal_point_; + string_type thousands_sep_; + std::string grouping_; +}; + template std::locale install_formatting_facets(std::locale const &in,cdata const &cd) @@ -362,6 +400,7 @@ std::locale install_formatting_facets(std::locale const &in,cdata const &cd) if(!std::has_facet(in)) { tmp=std::locale(tmp,new icu_formatters_cache(cd.locale)); } + tmp=std::locale(tmp, new icu_numpunct(cd.locale)); return tmp; } diff --git a/src/posix/numeric.cpp b/src/posix/numeric.cpp index 2bef81e2..25eadc26 100644 --- a/src/posix/numeric.cpp +++ b/src/posix/numeric.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -404,20 +405,16 @@ struct basic_numpunct { }; template -class num_punct_posix : public std::numpunct { +class num_punct_posix : public numpunct { public: typedef std::basic_string string_type; num_punct_posix(locale_t lc,size_t refs = 0) : - std::numpunct(refs) + numpunct(refs) { basic_numpunct np(lc); to_str(np.thousands_sep,thousands_sep_,lc); to_str(np.decimal_point,decimal_point_,lc); grouping_ = np.grouping; - if(thousands_sep_.size() > 1) - grouping_ = std::string(); - if(decimal_point_.size() > 1) - decimal_point_ = CharType('.'); } void to_str(std::string &s1,std::string &s2,locale_t /*lc*/) { @@ -429,11 +426,11 @@ class num_punct_posix : public std::numpunct { } virtual CharType do_decimal_point() const { - return *decimal_point_.c_str(); + return decimal_point_; } virtual CharType do_thousands_sep() const { - return *thousands_sep_.c_str(); + return thousands_sep_; } virtual std::string do_grouping() const { diff --git a/src/shared/ids.cpp b/src/shared/ids.cpp index 952fa85a..2d550303 100644 --- a/src/shared/ids.cpp +++ b/src/shared/ids.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace boost { namespace locale { @@ -25,10 +26,14 @@ namespace boost { std::locale::id converter::id; std::locale::id base_message_format::id; + std::locale::id numpunct::id; + std::locale::id numpunct::id; + #ifdef BOOST_LOCALE_ENABLE_CHAR16_T std::locale::id converter::id; std::locale::id base_message_format::id; + std::locale::id numpunct::id; #endif @@ -36,6 +41,7 @@ namespace boost { std::locale::id converter::id; std::locale::id base_message_format::id; + std::locale::id numpunct::id; #endif diff --git a/src/win32/numeric.cpp b/src/win32/numeric.cpp index 00bc94fd..70f96573 100644 --- a/src/win32/numeric.cpp +++ b/src/win32/numeric.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -119,11 +120,11 @@ class time_put_win : public std::time_put { template -class num_punct_win : public std::numpunct { +class num_punct_win : public numpunct { public: typedef std::basic_string string_type; num_punct_win(winlocale const &lc,size_t refs = 0) : - std::numpunct(refs) + numpunct(refs) { numeric_info np = wcsnumformat_l(lc) ; if(sizeof(CharType) == 1 && np.thousands_sep == L"\xA0") @@ -132,10 +133,6 @@ class num_punct_win : public std::numpunct { to_str(np.thousands_sep,thousands_sep_); to_str(np.decimal_point,decimal_point_); grouping_ = np.grouping; - if(thousands_sep_.size() > 1) - grouping_ = std::string(); - if(decimal_point_.size() > 1) - decimal_point_ = CharType('.'); } void to_str(std::wstring &s1,std::wstring &s2) @@ -147,28 +144,18 @@ class num_punct_win : public std::numpunct { { s2=conv::from_utf(s1,"UTF-8"); } - virtual CharType do_decimal_point() const + virtual string_type do_decimal_point() const { - return *decimal_point_.c_str(); + return decimal_point_; } - virtual CharType do_thousands_sep() const + virtual string_type do_thousands_sep() const { - return *thousands_sep_.c_str(); + return thousands_sep_; } virtual std::string do_grouping() const { return grouping_; } - virtual string_type do_truename() const - { - static const char t[]="true"; - return string_type(t,t+sizeof(t)-1); - } - virtual string_type do_falsename() const - { - static const char t[]="false"; - return string_type(t,t+sizeof(t)-1); - } private: string_type decimal_point_; string_type thousands_sep_; @@ -179,7 +166,7 @@ template std::locale create_formatting_impl(std::locale const &in,winlocale const &lc) { if(lc.is_c()) { - std::locale tmp(in,new std::numpunct_byname("C")); + std::locale tmp(in, new numpunct()); tmp=std::locale(tmp,new std::time_put_byname("C")); tmp = std::locale(tmp,new num_format(lc)); return tmp; @@ -195,12 +182,11 @@ std::locale create_formatting_impl(std::locale const &in,winlocale const &lc) template std::locale create_parsing_impl(std::locale const &in,winlocale const &lc) { - std::numpunct *np = 0; + std::locale tmp(in); if(lc.is_c()) - np = new std::numpunct_byname("C"); + tmp = std::locale(tmp, new numpunct()); else - np = new num_punct_win(lc); - std::locale tmp(in,np); + tmp = std::locale(tmp, new num_punct_win(lc)); tmp = std::locale(tmp,new util::base_num_parse()); return tmp; }