summaryrefslogtreecommitdiffstats
path: root/contrib/restricted/boost/locale/src/icu/numeric.cpp
diff options
context:
space:
mode:
authorthegeorg <[email protected]>2025-05-07 11:09:12 +0300
committerthegeorg <[email protected]>2025-05-07 11:25:22 +0300
commit4c98f14a2491da2bc1a9d40fed1d1682c7ec5dd6 (patch)
tree8142081775c27c8780fa0282a0273ee268e13b98 /contrib/restricted/boost/locale/src/icu/numeric.cpp
parent40b86c68b431bb65d67bba51ef9159066a833b68 (diff)
Update contrib/restricted/boost/locale to 1.88.0
commit_hash:87b595328ea79c6ba38cb973580804486ca4a3ff
Diffstat (limited to 'contrib/restricted/boost/locale/src/icu/numeric.cpp')
-rw-r--r--contrib/restricted/boost/locale/src/icu/numeric.cpp357
1 files changed, 357 insertions, 0 deletions
diff --git a/contrib/restricted/boost/locale/src/icu/numeric.cpp b/contrib/restricted/boost/locale/src/icu/numeric.cpp
new file mode 100644
index 00000000000..e54ab1c498a
--- /dev/null
+++ b/contrib/restricted/boost/locale/src/icu/numeric.cpp
@@ -0,0 +1,357 @@
+//
+// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
+// Copyright (c) 2024 Alexander Grund
+//
+// Distributed under the Boost Software License, Version 1.0.
+// https://www.boost.org/LICENSE_1_0.txt
+
+#include <boost/locale/formatting.hpp>
+#include "all_generator.hpp"
+#include "cdata.hpp"
+#include "formatter.hpp"
+#include "formatters_cache.hpp"
+#include <algorithm>
+#include <ios>
+#include <limits>
+#include <locale>
+#include <string>
+#include <type_traits>
+
+namespace boost { namespace locale { namespace impl_icu {
+
+ namespace detail {
+ template<typename T, typename PreferredType, typename AlternativeType>
+ struct choose_type_by_digits
+ : std::conditional<std::numeric_limits<T>::digits <= std::numeric_limits<PreferredType>::digits,
+ PreferredType,
+ AlternativeType> {};
+
+ template<typename T, bool integer = std::numeric_limits<T>::is_integer>
+ struct icu_format_type {
+ static_assert(sizeof(T) <= sizeof(int64_t), "Only up to 64 bit integer types are supported by ICU");
+ // ICU supports (only) int32_t and int64_t, use the former as long as it fits, else the latter
+ using large_type = typename choose_type_by_digits<T, int64_t, uint64_t>::type;
+ using type = typename choose_type_by_digits<T, int32_t, large_type>::type;
+ };
+ template<typename T>
+ struct icu_format_type<T, false> {
+ // Only float type ICU supports is double
+ using type = double;
+ };
+
+ template<typename ValueType>
+ static bool use_parent(std::ios_base& ios)
+ {
+ const uint64_t flg = ios_info::get(ios).display_flags();
+ if(flg == flags::posix)
+ return true;
+
+ if(!std::numeric_limits<ValueType>::is_integer)
+ return false;
+
+ if(flg == flags::number && (ios.flags() & std::ios_base::basefield) != std::ios_base::dec)
+ return true;
+ return false;
+ }
+ } // namespace detail
+
+ template<typename CharType>
+ class num_format : public std::num_put<CharType> {
+ public:
+ typedef typename std::num_put<CharType>::iter_type iter_type;
+ typedef std::basic_string<CharType> string_type;
+ typedef formatter<CharType> formatter_type;
+
+ num_format(const cdata& d, size_t refs = 0) : std::num_put<CharType>(refs), loc_(d.locale()), enc_(d.encoding())
+ {}
+
+ protected:
+ iter_type do_put(iter_type out, std::ios_base& ios, CharType fill, long val) const override
+ {
+ return do_real_put(out, ios, fill, val);
+ }
+ iter_type do_put(iter_type out, std::ios_base& ios, CharType fill, unsigned long val) const override
+ {
+ return do_real_put(out, ios, fill, val);
+ }
+ iter_type do_put(iter_type out, std::ios_base& ios, CharType fill, double val) const override
+ {
+ return do_real_put(out, ios, fill, val);
+ }
+ iter_type do_put(iter_type out, std::ios_base& ios, CharType fill, long double val) const override
+ {
+ return do_real_put(out, ios, fill, val);
+ }
+
+ iter_type do_put(iter_type out, std::ios_base& ios, CharType fill, long long val) const override
+ {
+ return do_real_put(out, ios, fill, val);
+ }
+ iter_type do_put(iter_type out, std::ios_base& ios, CharType fill, unsigned long long val) const override
+ {
+ return do_real_put(out, ios, fill, val);
+ }
+
+ private:
+ template<typename ValueType>
+ iter_type do_real_put(iter_type out, std::ios_base& ios, CharType fill, ValueType val) const
+ {
+ if(detail::use_parent<ValueType>(ios))
+ return std::num_put<CharType>::do_put(out, ios, fill, val);
+
+ const std::unique_ptr<formatter_type> formatter = formatter_type::create(ios, loc_, enc_);
+
+ if(!formatter)
+ return std::num_put<CharType>::do_put(out, ios, fill, val);
+
+ using icu_type = typename detail::icu_format_type<ValueType>::type;
+ size_t code_points;
+ const string_type str = formatter->format(static_cast<icu_type>(val), code_points);
+
+ std::streamsize on_left = 0, on_right = 0, points = code_points;
+ if(points < ios.width()) {
+ const std::streamsize n = ios.width() - points;
+
+ const std::ios_base::fmtflags flags = ios.flags() & std::ios_base::adjustfield;
+
+ // We do not really know internal point, so we assume that it does not
+ // exist. So according to the standard field should be right aligned
+ if(flags != std::ios_base::left)
+ on_left = n;
+ on_right = n - on_left;
+ }
+ while(on_left > 0) {
+ *out++ = fill;
+ on_left--;
+ }
+ std::copy(str.begin(), str.end(), out);
+ while(on_right > 0) {
+ *out++ = fill;
+ on_right--;
+ }
+ ios.width(0);
+ return out;
+ }
+
+ icu::Locale loc_;
+ std::string enc_;
+
+ }; // num_format
+
+ template<typename CharType>
+ class num_parse : public std::num_get<CharType> {
+ public:
+ num_parse(const cdata& d, size_t refs = 0) : std::num_get<CharType>(refs), loc_(d.locale()), enc_(d.encoding())
+ {}
+
+ protected:
+ typedef typename std::num_get<CharType>::iter_type iter_type;
+ typedef std::basic_string<CharType> string_type;
+ typedef formatter<CharType> formatter_type;
+ typedef std::basic_istream<CharType> stream_type;
+
+ iter_type
+ do_get(iter_type in, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, long& val) const override
+ {
+ return do_real_get(in, end, ios, err, val);
+ }
+
+ iter_type do_get(iter_type in,
+ iter_type end,
+ std::ios_base& ios,
+ std::ios_base::iostate& err,
+ unsigned short& val) const override
+ {
+ return do_real_get(in, end, ios, err, val);
+ }
+
+ iter_type do_get(iter_type in,
+ iter_type end,
+ std::ios_base& ios,
+ std::ios_base::iostate& err,
+ unsigned int& val) const override
+ {
+ return do_real_get(in, end, ios, err, val);
+ }
+
+ iter_type do_get(iter_type in,
+ iter_type end,
+ std::ios_base& ios,
+ std::ios_base::iostate& err,
+ unsigned long& val) const override
+ {
+ return do_real_get(in, end, ios, err, val);
+ }
+
+ iter_type
+ do_get(iter_type in, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, float& val) const override
+ {
+ return do_real_get(in, end, ios, err, val);
+ }
+
+ iter_type
+ do_get(iter_type in, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, double& val) const override
+ {
+ return do_real_get(in, end, ios, err, val);
+ }
+
+ iter_type do_get(iter_type in,
+ iter_type end,
+ std::ios_base& ios,
+ std::ios_base::iostate& err,
+ long double& val) const override
+ {
+ return do_real_get(in, end, ios, err, val);
+ }
+
+ iter_type do_get(iter_type in,
+ iter_type end,
+ std::ios_base& ios,
+ std::ios_base::iostate& err,
+ long long& val) const override
+ {
+ return do_real_get(in, end, ios, err, val);
+ }
+
+ iter_type do_get(iter_type in,
+ iter_type end,
+ std::ios_base& ios,
+ std::ios_base::iostate& err,
+ unsigned long long& val) const override
+ {
+ return do_real_get(in, end, ios, err, val);
+ }
+
+ private:
+ //
+ // This is not really an efficient solution, but it works
+ //
+ template<typename ValueType>
+ iter_type
+ do_real_get(iter_type in, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, ValueType& val) const
+ {
+ stream_type* stream_ptr = dynamic_cast<stream_type*>(&ios);
+ if(!stream_ptr || detail::use_parent<ValueType>(ios))
+ return std::num_get<CharType>::do_get(in, end, ios, err, val);
+
+ const std::unique_ptr<formatter_type> formatter = formatter_type::create(ios, loc_, enc_);
+ if(!formatter)
+ return std::num_get<CharType>::do_get(in, end, ios, err, val);
+
+ string_type tmp;
+ tmp.reserve(64);
+
+ CharType c;
+ while(in != end && (((c = *in) <= 32 && (c > 0)) || c == 127)) // Assuming that ASCII is a subset
+ ++in;
+
+ while(tmp.size() < 4096 && in != end && *in != '\n')
+ tmp += *in++;
+
+ using icu_type = typename detail::icu_format_type<ValueType>::type;
+ icu_type value;
+ size_t parsed_chars;
+
+ if((parsed_chars = formatter->parse(tmp, value)) == 0 || !is_losless_castable<ValueType>(value))
+ err |= std::ios_base::failbit;
+ else
+ val = static_cast<ValueType>(value);
+
+ for(size_t n = tmp.size(); n > parsed_chars; n--)
+ stream_ptr->putback(tmp[n - 1]);
+
+ in = iter_type(*stream_ptr);
+
+ if(in == end)
+ err |= std::ios_base::eofbit;
+ return in;
+ }
+
+ BOOST_LOCALE_START_CONST_CONDITION
+ template<typename TargetType, typename SrcType>
+ bool is_losless_castable(SrcType v) const
+ {
+ typedef std::numeric_limits<TargetType> target_limits;
+ typedef std::numeric_limits<SrcType> casted_limits;
+ if(v < 0 && !target_limits::is_signed)
+ return false;
+
+ constexpr TargetType max_val = target_limits::max();
+
+ if(sizeof(SrcType) > sizeof(TargetType) && v > static_cast<SrcType>(max_val))
+ return false;
+
+ if(target_limits::is_integer == casted_limits::is_integer)
+ return true;
+
+ if(target_limits::is_integer) { // and source is not
+ if(static_cast<SrcType>(static_cast<TargetType>(v)) != v)
+ return false;
+ }
+ return true;
+ }
+ BOOST_LOCALE_END_CONST_CONDITION
+
+ icu::Locale loc_;
+ std::string enc_;
+ };
+
+ template<typename CharType>
+ std::locale install_formatting_facets(const std::locale& in, const cdata& cd)
+ {
+ std::locale tmp = std::locale(in, new num_format<CharType>(cd));
+ if(!std::has_facet<formatters_cache>(in))
+ tmp = std::locale(tmp, new formatters_cache(cd.locale()));
+ return tmp;
+ }
+
+ template<typename CharType>
+ std::locale install_parsing_facets(const std::locale& in, const cdata& cd)
+ {
+ std::locale tmp = std::locale(in, new num_parse<CharType>(cd));
+ if(!std::has_facet<formatters_cache>(in))
+ tmp = std::locale(tmp, new formatters_cache(cd.locale()));
+ return tmp;
+ }
+
+ std::locale create_formatting(const std::locale& in, const cdata& cd, char_facet_t type)
+ {
+ switch(type) {
+ case char_facet_t::nochar: break;
+ case char_facet_t::char_f: return install_formatting_facets<char>(in, cd);
+ case char_facet_t::wchar_f: return install_formatting_facets<wchar_t>(in, cd);
+#ifdef __cpp_char8_t
+ case char_facet_t::char8_f: break; // std-facet not available (yet)
+#endif
+#ifdef BOOST_LOCALE_ENABLE_CHAR16_T
+ case char_facet_t::char16_f: return install_formatting_facets<char16_t>(in, cd);
+#endif
+#ifdef BOOST_LOCALE_ENABLE_CHAR32_T
+ case char_facet_t::char32_f: return install_formatting_facets<char32_t>(in, cd);
+#endif
+ }
+ return in;
+ }
+
+ std::locale create_parsing(const std::locale& in, const cdata& cd, char_facet_t type)
+ {
+ switch(type) {
+ case char_facet_t::nochar: break;
+ case char_facet_t::char_f: return install_parsing_facets<char>(in, cd);
+ case char_facet_t::wchar_f: return install_parsing_facets<wchar_t>(in, cd);
+#ifdef __cpp_char8_t
+ case char_facet_t::char8_f: break; // std-facet not available (yet)
+#endif
+#ifdef BOOST_LOCALE_ENABLE_CHAR16_T
+ case char_facet_t::char16_f: return install_parsing_facets<char16_t>(in, cd);
+#endif
+#ifdef BOOST_LOCALE_ENABLE_CHAR32_T
+ case char_facet_t::char32_f: return install_parsing_facets<char32_t>(in, cd);
+#endif
+ }
+ return in;
+ }
+
+}}} // namespace boost::locale::impl_icu
+
+// boostinspect:nominmax