File indexing completed on 2025-07-01 08:18:48
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 #if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6)
0060 __attribute__((no_sanitize("unsigned-integer-overflow")))
0061 #endif
0062 inline
0063 typename boost::make_unsigned<T>::type lcast_to_unsigned(const T value) noexcept {
0064 typedef typename boost::make_unsigned<T>::type result_type;
0065 return value < 0
0066 ? static_cast<result_type>(0u - static_cast<result_type>(value))
0067 : static_cast<result_type>(value);
0068 }
0069 }
0070
0071 namespace detail
0072 {
0073 template <class Traits, class T, class CharT>
0074 class lcast_put_unsigned: boost::noncopyable {
0075 typedef typename Traits::int_type int_type;
0076 typename boost::conditional<
0077 (sizeof(unsigned) > sizeof(T))
0078 , unsigned
0079 , T
0080 >::type m_value;
0081 CharT* m_finish;
0082 CharT const m_czero;
0083 int_type const m_zero;
0084
0085 public:
0086 lcast_put_unsigned(const T n_param, CharT* finish) noexcept
0087 : m_value(n_param), m_finish(finish)
0088 , m_czero(lcast_char_constants<CharT>::zero), m_zero(Traits::to_int_type(m_czero))
0089 {
0090 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
0091 static_assert(!std::numeric_limits<T>::is_signed, "");
0092 #endif
0093 }
0094
0095 CharT* convert() {
0096 #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
0097 std::locale loc;
0098 if (loc == std::locale::classic()) {
0099 return main_convert_loop();
0100 }
0101
0102 typedef std::numpunct<CharT> numpunct;
0103 numpunct const& np = BOOST_USE_FACET(numpunct, loc);
0104 std::string const grouping = np.grouping();
0105 std::string::size_type const grouping_size = grouping.size();
0106
0107 if (!grouping_size || grouping[0] <= 0) {
0108 return main_convert_loop();
0109 }
0110
0111 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
0112
0113 static_assert(std::numeric_limits<T>::digits10 < CHAR_MAX, "");
0114 #endif
0115 CharT const thousands_sep = np.thousands_sep();
0116 std::string::size_type group = 0;
0117 char last_grp_size = grouping[0];
0118 char left = last_grp_size;
0119
0120 do {
0121 if (left == 0) {
0122 ++group;
0123 if (group < grouping_size) {
0124 char const grp_size = grouping[group];
0125 last_grp_size = (grp_size <= 0 ? static_cast<char>(CHAR_MAX) : grp_size);
0126 }
0127
0128 left = last_grp_size;
0129 --m_finish;
0130 Traits::assign(*m_finish, thousands_sep);
0131 }
0132
0133 --left;
0134 } while (main_convert_iteration());
0135
0136 return m_finish;
0137 #else
0138 return main_convert_loop();
0139 #endif
0140 }
0141
0142 private:
0143 inline bool main_convert_iteration() noexcept {
0144 --m_finish;
0145 int_type const digit = static_cast<int_type>(m_value % 10U);
0146 Traits::assign(*m_finish, Traits::to_char_type(m_zero + digit));
0147 m_value /= 10;
0148 return !!m_value;
0149 }
0150
0151 inline CharT* main_convert_loop() noexcept {
0152 while (main_convert_iteration());
0153 return m_finish;
0154 }
0155 };
0156 }
0157
0158 namespace detail
0159 {
0160 template <class Traits, class T, class CharT>
0161 class lcast_ret_unsigned: boost::noncopyable {
0162 bool m_multiplier_overflowed;
0163 T m_multiplier;
0164 T& m_value;
0165 const CharT* const m_begin;
0166 const CharT* m_end;
0167
0168 public:
0169 lcast_ret_unsigned(T& value, const CharT* const begin, const CharT* end) noexcept
0170 : m_multiplier_overflowed(false), m_multiplier(1), m_value(value), m_begin(begin), m_end(end)
0171 {
0172 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
0173 static_assert(!std::numeric_limits<T>::is_signed, "");
0174
0175
0176
0177
0178
0179
0180 static_assert(std::numeric_limits<T>::is_specialized,
0181 "std::numeric_limits are not specialized for integral type passed to boost::lexical_cast"
0182 );
0183 #endif
0184 }
0185
0186 inline bool convert() {
0187 CharT const czero = lcast_char_constants<CharT>::zero;
0188 --m_end;
0189 m_value = static_cast<T>(0);
0190
0191 if (m_begin > m_end || *m_end < czero || *m_end >= czero + 10)
0192 return false;
0193 m_value = static_cast<T>(*m_end - czero);
0194 --m_end;
0195
0196 #ifdef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
0197 return main_convert_loop();
0198 #else
0199 std::locale loc;
0200 if (loc == std::locale::classic()) {
0201 return main_convert_loop();
0202 }
0203
0204 typedef std::numpunct<CharT> numpunct;
0205 numpunct const& np = BOOST_USE_FACET(numpunct, loc);
0206 std::string const& grouping = np.grouping();
0207 std::string::size_type const grouping_size = grouping.size();
0208
0209
0210
0211
0212 if (!grouping_size || grouping[0] <= 0) {
0213 return main_convert_loop();
0214 }
0215
0216 unsigned char current_grouping = 0;
0217 CharT const thousands_sep = np.thousands_sep();
0218 char remained = static_cast<char>(grouping[current_grouping] - 1);
0219
0220 for (;m_end >= m_begin; --m_end)
0221 {
0222 if (remained) {
0223 if (!main_convert_iteration()) {
0224 return false;
0225 }
0226 --remained;
0227 } else {
0228 if ( !Traits::eq(*m_end, thousands_sep) )
0229 {
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241 return main_convert_loop();
0242 } else {
0243 if (m_begin == m_end) return false;
0244 if (current_grouping < grouping_size - 1) ++current_grouping;
0245 remained = grouping[current_grouping];
0246 }
0247 }
0248 }
0249
0250 return true;
0251 #endif
0252 }
0253
0254 private:
0255
0256
0257 #if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6)
0258 __attribute__((no_sanitize("unsigned-integer-overflow")))
0259 #endif
0260 inline bool main_convert_iteration() noexcept {
0261 CharT const czero = lcast_char_constants<CharT>::zero;
0262 T const maxv = (std::numeric_limits<T>::max)();
0263
0264 m_multiplier_overflowed = m_multiplier_overflowed || (maxv/10 < m_multiplier);
0265 m_multiplier = static_cast<T>(m_multiplier * 10);
0266
0267 T const dig_value = static_cast<T>(*m_end - czero);
0268 T const new_sub_value = static_cast<T>(m_multiplier * dig_value);
0269
0270
0271
0272 if (*m_end < czero || *m_end >= czero + 10
0273 || (dig_value && (
0274 m_multiplier_overflowed
0275 || static_cast<T>(maxv / dig_value) < m_multiplier
0276 || static_cast<T>(maxv - new_sub_value) < m_value
0277 ))
0278 ) return false;
0279
0280 m_value = static_cast<T>(m_value + new_sub_value);
0281
0282 return true;
0283 }
0284
0285 bool main_convert_loop() noexcept {
0286 for ( ; m_end >= m_begin; --m_end) {
0287 if (!main_convert_iteration()) {
0288 return false;
0289 }
0290 }
0291
0292 return true;
0293 }
0294 };
0295 }
0296 }
0297
0298 #endif
0299