File indexing completed on 2025-01-18 09:39:13
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #ifndef BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP
0019 #define BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP
0020
0021 #include <boost/config.hpp>
0022 #ifdef BOOST_HAS_PRAGMA_ONCE
0023 # pragma once
0024 #endif
0025
0026 #include <climits>
0027 #include <cstddef>
0028 #include <string>
0029 #include <cstring>
0030 #include <cstdio>
0031 #include <boost/limits.hpp>
0032 #include <boost/type_traits/conditional.hpp>
0033 #include <boost/detail/workaround.hpp>
0034
0035
0036 #ifndef BOOST_NO_STD_LOCALE
0037 # include <locale>
0038 #else
0039 # ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
0040
0041
0042
0043
0044 # error "Unable to use <locale> header. Define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE to force "
0045 # error "boost::lexical_cast to use only 'C' locale during conversions."
0046 # endif
0047 #endif
0048
0049 #include <boost/lexical_cast/detail/lcast_char_constants.hpp>
0050 #include <boost/type_traits/make_unsigned.hpp>
0051 #include <boost/type_traits/is_signed.hpp>
0052 #include <boost/core/noncopyable.hpp>
0053
0054 namespace boost
0055 {
0056 namespace detail
0057 {
0058 template<class T>
0059 inline
0060 typename boost::make_unsigned<T>::type lcast_to_unsigned(const T value) noexcept {
0061 typedef typename boost::make_unsigned<T>::type result_type;
0062 return value < 0
0063 ? static_cast<result_type>(0u - static_cast<result_type>(value))
0064 : static_cast<result_type>(value);
0065 }
0066 }
0067
0068 namespace detail
0069 {
0070 template <class Traits, class T, class CharT>
0071 class lcast_put_unsigned: boost::noncopyable {
0072 typedef typename Traits::int_type int_type;
0073 typename boost::conditional<
0074 (sizeof(unsigned) > sizeof(T))
0075 , unsigned
0076 , T
0077 >::type m_value;
0078 CharT* m_finish;
0079 CharT const m_czero;
0080 int_type const m_zero;
0081
0082 public:
0083 lcast_put_unsigned(const T n_param, CharT* finish) noexcept
0084 : m_value(n_param), m_finish(finish)
0085 , m_czero(lcast_char_constants<CharT>::zero), m_zero(Traits::to_int_type(m_czero))
0086 {
0087 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
0088 static_assert(!std::numeric_limits<T>::is_signed, "");
0089 #endif
0090 }
0091
0092 CharT* convert() {
0093 #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
0094 std::locale loc;
0095 if (loc == std::locale::classic()) {
0096 return main_convert_loop();
0097 }
0098
0099 typedef std::numpunct<CharT> numpunct;
0100 numpunct const& np = BOOST_USE_FACET(numpunct, loc);
0101 std::string const grouping = np.grouping();
0102 std::string::size_type const grouping_size = grouping.size();
0103
0104 if (!grouping_size || grouping[0] <= 0) {
0105 return main_convert_loop();
0106 }
0107
0108 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
0109
0110 static_assert(std::numeric_limits<T>::digits10 < CHAR_MAX, "");
0111 #endif
0112 CharT const thousands_sep = np.thousands_sep();
0113 std::string::size_type group = 0;
0114 char last_grp_size = grouping[0];
0115 char left = last_grp_size;
0116
0117 do {
0118 if (left == 0) {
0119 ++group;
0120 if (group < grouping_size) {
0121 char const grp_size = grouping[group];
0122 last_grp_size = (grp_size <= 0 ? static_cast<char>(CHAR_MAX) : grp_size);
0123 }
0124
0125 left = last_grp_size;
0126 --m_finish;
0127 Traits::assign(*m_finish, thousands_sep);
0128 }
0129
0130 --left;
0131 } while (main_convert_iteration());
0132
0133 return m_finish;
0134 #else
0135 return main_convert_loop();
0136 #endif
0137 }
0138
0139 private:
0140 inline bool main_convert_iteration() noexcept {
0141 --m_finish;
0142 int_type const digit = static_cast<int_type>(m_value % 10U);
0143 Traits::assign(*m_finish, Traits::to_char_type(m_zero + digit));
0144 m_value /= 10;
0145 return !!m_value;
0146 }
0147
0148 inline CharT* main_convert_loop() noexcept {
0149 while (main_convert_iteration());
0150 return m_finish;
0151 }
0152 };
0153 }
0154
0155 namespace detail
0156 {
0157 template <class Traits, class T, class CharT>
0158 class lcast_ret_unsigned: boost::noncopyable {
0159 bool m_multiplier_overflowed;
0160 T m_multiplier;
0161 T& m_value;
0162 const CharT* const m_begin;
0163 const CharT* m_end;
0164
0165 public:
0166 lcast_ret_unsigned(T& value, const CharT* const begin, const CharT* end) noexcept
0167 : m_multiplier_overflowed(false), m_multiplier(1), m_value(value), m_begin(begin), m_end(end)
0168 {
0169 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
0170 static_assert(!std::numeric_limits<T>::is_signed, "");
0171
0172
0173
0174
0175
0176
0177 static_assert(std::numeric_limits<T>::is_specialized,
0178 "std::numeric_limits are not specialized for integral type passed to boost::lexical_cast"
0179 );
0180 #endif
0181 }
0182
0183 inline bool convert() {
0184 CharT const czero = lcast_char_constants<CharT>::zero;
0185 --m_end;
0186 m_value = static_cast<T>(0);
0187
0188 if (m_begin > m_end || *m_end < czero || *m_end >= czero + 10)
0189 return false;
0190 m_value = static_cast<T>(*m_end - czero);
0191 --m_end;
0192
0193 #ifdef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
0194 return main_convert_loop();
0195 #else
0196 std::locale loc;
0197 if (loc == std::locale::classic()) {
0198 return main_convert_loop();
0199 }
0200
0201 typedef std::numpunct<CharT> numpunct;
0202 numpunct const& np = BOOST_USE_FACET(numpunct, loc);
0203 std::string const& grouping = np.grouping();
0204 std::string::size_type const grouping_size = grouping.size();
0205
0206
0207
0208
0209 if (!grouping_size || grouping[0] <= 0) {
0210 return main_convert_loop();
0211 }
0212
0213 unsigned char current_grouping = 0;
0214 CharT const thousands_sep = np.thousands_sep();
0215 char remained = static_cast<char>(grouping[current_grouping] - 1);
0216
0217 for (;m_end >= m_begin; --m_end)
0218 {
0219 if (remained) {
0220 if (!main_convert_iteration()) {
0221 return false;
0222 }
0223 --remained;
0224 } else {
0225 if ( !Traits::eq(*m_end, thousands_sep) )
0226 {
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238 return main_convert_loop();
0239 } else {
0240 if (m_begin == m_end) return false;
0241 if (current_grouping < grouping_size - 1) ++current_grouping;
0242 remained = grouping[current_grouping];
0243 }
0244 }
0245 }
0246
0247 return true;
0248 #endif
0249 }
0250
0251 private:
0252
0253
0254 inline bool main_convert_iteration() noexcept {
0255 CharT const czero = lcast_char_constants<CharT>::zero;
0256 T const maxv = (std::numeric_limits<T>::max)();
0257
0258 m_multiplier_overflowed = m_multiplier_overflowed || (maxv/10 < m_multiplier);
0259 m_multiplier = static_cast<T>(m_multiplier * 10);
0260
0261 T const dig_value = static_cast<T>(*m_end - czero);
0262 T const new_sub_value = static_cast<T>(m_multiplier * dig_value);
0263
0264
0265
0266 if (*m_end < czero || *m_end >= czero + 10
0267 || (dig_value && (
0268 m_multiplier_overflowed
0269 || static_cast<T>(maxv / dig_value) < m_multiplier
0270 || static_cast<T>(maxv - new_sub_value) < m_value
0271 ))
0272 ) return false;
0273
0274 m_value = static_cast<T>(m_value + new_sub_value);
0275
0276 return true;
0277 }
0278
0279 bool main_convert_loop() noexcept {
0280 for ( ; m_end >= m_begin; --m_end) {
0281 if (!main_convert_iteration()) {
0282 return false;
0283 }
0284 }
0285
0286 return true;
0287 }
0288 };
0289 }
0290 }
0291
0292 #endif
0293