annotate DEPENDENCIES/generic/include/boost/lexical_cast/detail/lcast_unsigned_converters.hpp @ 125:34e428693f5d vext

Vext -> Repoint
author Chris Cannam
date Thu, 14 Jun 2018 11:15:39 +0100
parents f46d142149f5
children
rev   line source
Chris@102 1 // Copyright Kevlin Henney, 2000-2005.
Chris@102 2 // Copyright Alexander Nasonov, 2006-2010.
Chris@102 3 // Copyright Antony Polukhin, 2011-2014.
Chris@102 4 //
Chris@102 5 // Distributed under the Boost Software License, Version 1.0. (See
Chris@102 6 // accompanying file LICENSE_1_0.txt or copy at
Chris@102 7 // http://www.boost.org/LICENSE_1_0.txt)
Chris@102 8 //
Chris@102 9 // what: lexical_cast custom keyword cast
Chris@102 10 // who: contributed by Kevlin Henney,
Chris@102 11 // enhanced with contributions from Terje Slettebo,
Chris@102 12 // with additional fixes and suggestions from Gennaro Prota,
Chris@102 13 // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov,
Chris@102 14 // Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann,
Chris@102 15 // Cheng Yang, Matthew Bradbury, David W. Birdsall, Pavel Korzh and other Boosters
Chris@102 16 // when: November 2000, March 2003, June 2005, June 2006, March 2011 - 2014
Chris@102 17
Chris@102 18 #ifndef BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP
Chris@102 19 #define BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP
Chris@102 20
Chris@102 21 #include <boost/config.hpp>
Chris@102 22 #ifdef BOOST_HAS_PRAGMA_ONCE
Chris@102 23 # pragma once
Chris@102 24 #endif
Chris@102 25
Chris@102 26 #include <climits>
Chris@102 27 #include <cstddef>
Chris@102 28 #include <string>
Chris@102 29 #include <cstring>
Chris@102 30 #include <cstdio>
Chris@102 31 #include <boost/limits.hpp>
Chris@102 32 #include <boost/mpl/if.hpp>
Chris@102 33 #include <boost/type_traits/ice.hpp>
Chris@102 34 #include <boost/static_assert.hpp>
Chris@102 35 #include <boost/detail/workaround.hpp>
Chris@102 36
Chris@102 37
Chris@102 38 #ifndef BOOST_NO_STD_LOCALE
Chris@102 39 # include <locale>
Chris@102 40 #else
Chris@102 41 # ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
Chris@102 42 // Getting error at this point means, that your STL library is old/lame/misconfigured.
Chris@102 43 // If nothing can be done with STL library, define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE,
Chris@102 44 // but beware: lexical_cast will understand only 'C' locale delimeters and thousands
Chris@102 45 // separators.
Chris@102 46 # error "Unable to use <locale> header. Define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE to force "
Chris@102 47 # error "boost::lexical_cast to use only 'C' locale during conversions."
Chris@102 48 # endif
Chris@102 49 #endif
Chris@102 50
Chris@102 51 #include <boost/lexical_cast/detail/lcast_char_constants.hpp>
Chris@102 52 #include <boost/type_traits/make_unsigned.hpp>
Chris@102 53 #include <boost/type_traits/is_signed.hpp>
Chris@102 54 #include <boost/noncopyable.hpp>
Chris@102 55
Chris@102 56 namespace boost
Chris@102 57 {
Chris@102 58 namespace detail // lcast_to_unsigned
Chris@102 59 {
Chris@102 60 template<class T>
Chris@102 61 inline
Chris@102 62 BOOST_DEDUCED_TYPENAME boost::make_unsigned<T>::type lcast_to_unsigned(const T value) BOOST_NOEXCEPT {
Chris@102 63 typedef BOOST_DEDUCED_TYPENAME boost::make_unsigned<T>::type result_type;
Chris@102 64 return value < 0
Chris@102 65 ? static_cast<result_type>(0u - static_cast<result_type>(value))
Chris@102 66 : static_cast<result_type>(value);
Chris@102 67 }
Chris@102 68 }
Chris@102 69
Chris@102 70 namespace detail // lcast_put_unsigned
Chris@102 71 {
Chris@102 72 template <class Traits, class T, class CharT>
Chris@102 73 class lcast_put_unsigned: boost::noncopyable {
Chris@102 74 typedef BOOST_DEDUCED_TYPENAME Traits::int_type int_type;
Chris@102 75 BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
Chris@102 76 (sizeof(int_type) > sizeof(T))
Chris@102 77 , int_type
Chris@102 78 , T
Chris@102 79 >::type m_value;
Chris@102 80 CharT* m_finish;
Chris@102 81 CharT const m_czero;
Chris@102 82 int_type const m_zero;
Chris@102 83
Chris@102 84 public:
Chris@102 85 lcast_put_unsigned(const T n_param, CharT* finish) BOOST_NOEXCEPT
Chris@102 86 : m_value(n_param), m_finish(finish)
Chris@102 87 , m_czero(lcast_char_constants<CharT>::zero), m_zero(Traits::to_int_type(m_czero))
Chris@102 88 {
Chris@102 89 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
Chris@102 90 BOOST_STATIC_ASSERT(!std::numeric_limits<T>::is_signed);
Chris@102 91 #endif
Chris@102 92 }
Chris@102 93
Chris@102 94 CharT* convert() {
Chris@102 95 #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
Chris@102 96 std::locale loc;
Chris@102 97 if (loc == std::locale::classic()) {
Chris@102 98 return main_convert_loop();
Chris@102 99 }
Chris@102 100
Chris@102 101 typedef std::numpunct<CharT> numpunct;
Chris@102 102 numpunct const& np = BOOST_USE_FACET(numpunct, loc);
Chris@102 103 std::string const grouping = np.grouping();
Chris@102 104 std::string::size_type const grouping_size = grouping.size();
Chris@102 105
Chris@102 106 if (!grouping_size || grouping[0] <= 0) {
Chris@102 107 return main_convert_loop();
Chris@102 108 }
Chris@102 109
Chris@102 110 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
Chris@102 111 // Check that ulimited group is unreachable:
Chris@102 112 BOOST_STATIC_ASSERT(std::numeric_limits<T>::digits10 < CHAR_MAX);
Chris@102 113 #endif
Chris@102 114 CharT const thousands_sep = np.thousands_sep();
Chris@102 115 std::string::size_type group = 0; // current group number
Chris@102 116 char last_grp_size = grouping[0];
Chris@102 117 char left = last_grp_size;
Chris@102 118
Chris@102 119 do {
Chris@102 120 if (left == 0) {
Chris@102 121 ++group;
Chris@102 122 if (group < grouping_size) {
Chris@102 123 char const grp_size = grouping[group];
Chris@102 124 last_grp_size = (grp_size <= 0 ? static_cast<char>(CHAR_MAX) : grp_size);
Chris@102 125 }
Chris@102 126
Chris@102 127 left = last_grp_size;
Chris@102 128 --m_finish;
Chris@102 129 Traits::assign(*m_finish, thousands_sep);
Chris@102 130 }
Chris@102 131
Chris@102 132 --left;
Chris@102 133 } while (main_convert_iteration());
Chris@102 134
Chris@102 135 return m_finish;
Chris@102 136 #else
Chris@102 137 return main_convert_loop();
Chris@102 138 #endif
Chris@102 139 }
Chris@102 140
Chris@102 141 private:
Chris@102 142 inline bool main_convert_iteration() BOOST_NOEXCEPT {
Chris@102 143 --m_finish;
Chris@102 144 int_type const digit = static_cast<int_type>(m_value % 10U);
Chris@102 145 Traits::assign(*m_finish, Traits::to_char_type(m_zero + digit));
Chris@102 146 m_value /= 10;
Chris@102 147 return !!m_value; // suppressing warnings
Chris@102 148 }
Chris@102 149
Chris@102 150 inline CharT* main_convert_loop() BOOST_NOEXCEPT {
Chris@102 151 while (main_convert_iteration());
Chris@102 152 return m_finish;
Chris@102 153 }
Chris@102 154 };
Chris@102 155 }
Chris@102 156
Chris@102 157 namespace detail // lcast_ret_unsigned
Chris@102 158 {
Chris@102 159 template <class Traits, class T, class CharT>
Chris@102 160 class lcast_ret_unsigned: boost::noncopyable {
Chris@102 161 bool m_multiplier_overflowed;
Chris@102 162 T m_multiplier;
Chris@102 163 T& m_value;
Chris@102 164 const CharT* const m_begin;
Chris@102 165 const CharT* m_end;
Chris@102 166
Chris@102 167 public:
Chris@102 168 lcast_ret_unsigned(T& value, const CharT* const begin, const CharT* end) BOOST_NOEXCEPT
Chris@102 169 : m_multiplier_overflowed(false), m_multiplier(1), m_value(value), m_begin(begin), m_end(end)
Chris@102 170 {
Chris@102 171 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
Chris@102 172 BOOST_STATIC_ASSERT(!std::numeric_limits<T>::is_signed);
Chris@102 173
Chris@102 174 // GCC when used with flag -std=c++0x may not have std::numeric_limits
Chris@102 175 // specializations for __int128 and unsigned __int128 types.
Chris@102 176 // Try compilation with -std=gnu++0x or -std=gnu++11.
Chris@102 177 //
Chris@102 178 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40856
Chris@102 179 BOOST_STATIC_ASSERT_MSG(std::numeric_limits<T>::is_specialized,
Chris@102 180 "std::numeric_limits are not specialized for integral type passed to boost::lexical_cast"
Chris@102 181 );
Chris@102 182 #endif
Chris@102 183 }
Chris@102 184
Chris@102 185 inline bool convert() {
Chris@102 186 CharT const czero = lcast_char_constants<CharT>::zero;
Chris@102 187 --m_end;
Chris@102 188 m_value = static_cast<T>(0);
Chris@102 189
Chris@102 190 if (m_begin > m_end || *m_end < czero || *m_end >= czero + 10)
Chris@102 191 return false;
Chris@102 192 m_value = static_cast<T>(*m_end - czero);
Chris@102 193 --m_end;
Chris@102 194
Chris@102 195 #ifdef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
Chris@102 196 return main_convert_loop();
Chris@102 197 #else
Chris@102 198 std::locale loc;
Chris@102 199 if (loc == std::locale::classic()) {
Chris@102 200 return main_convert_loop();
Chris@102 201 }
Chris@102 202
Chris@102 203 typedef std::numpunct<CharT> numpunct;
Chris@102 204 numpunct const& np = BOOST_USE_FACET(numpunct, loc);
Chris@102 205 std::string const& grouping = np.grouping();
Chris@102 206 std::string::size_type const grouping_size = grouping.size();
Chris@102 207
Chris@102 208 /* According to Programming languages - C++
Chris@102 209 * we MUST check for correct grouping
Chris@102 210 */
Chris@102 211 if (!grouping_size || grouping[0] <= 0) {
Chris@102 212 return main_convert_loop();
Chris@102 213 }
Chris@102 214
Chris@102 215 unsigned char current_grouping = 0;
Chris@102 216 CharT const thousands_sep = np.thousands_sep();
Chris@102 217 char remained = static_cast<char>(grouping[current_grouping] - 1);
Chris@102 218
Chris@102 219 for (;m_end >= m_begin; --m_end)
Chris@102 220 {
Chris@102 221 if (remained) {
Chris@102 222 if (!main_convert_iteration()) {
Chris@102 223 return false;
Chris@102 224 }
Chris@102 225 --remained;
Chris@102 226 } else {
Chris@102 227 if ( !Traits::eq(*m_end, thousands_sep) ) //|| begin == end ) return false;
Chris@102 228 {
Chris@102 229 /*
Chris@102 230 * According to Programming languages - C++
Chris@102 231 * Digit grouping is checked. That is, the positions of discarded
Chris@102 232 * separators is examined for consistency with
Chris@102 233 * use_facet<numpunct<charT> >(loc ).grouping()
Chris@102 234 *
Chris@102 235 * BUT what if there is no separators at all and grouping()
Chris@102 236 * is not empty? Well, we have no extraced separators, so we
Chris@102 237 * won`t check them for consistency. This will allow us to
Chris@102 238 * work with "C" locale from other locales
Chris@102 239 */
Chris@102 240 return main_convert_loop();
Chris@102 241 } else {
Chris@102 242 if (m_begin == m_end) return false;
Chris@102 243 if (current_grouping < grouping_size - 1) ++current_grouping;
Chris@102 244 remained = grouping[current_grouping];
Chris@102 245 }
Chris@102 246 }
Chris@102 247 } /*for*/
Chris@102 248
Chris@102 249 return true;
Chris@102 250 #endif
Chris@102 251 }
Chris@102 252
Chris@102 253 private:
Chris@102 254 // Iteration that does not care about grouping/separators and assumes that all
Chris@102 255 // input characters are digits
Chris@102 256 inline bool main_convert_iteration() BOOST_NOEXCEPT {
Chris@102 257 CharT const czero = lcast_char_constants<CharT>::zero;
Chris@102 258 T const maxv = (std::numeric_limits<T>::max)();
Chris@102 259
Chris@102 260 m_multiplier_overflowed = m_multiplier_overflowed || (maxv/10 < m_multiplier);
Chris@102 261 m_multiplier = static_cast<T>(m_multiplier * 10);
Chris@102 262
Chris@102 263 T const dig_value = static_cast<T>(*m_end - czero);
Chris@102 264 T const new_sub_value = static_cast<T>(m_multiplier * dig_value);
Chris@102 265
Chris@102 266 // We must correctly handle situations like `000000000000000000000000000001`.
Chris@102 267 // So we take care of overflow only if `dig_value` is not '0'.
Chris@102 268 if (*m_end < czero || *m_end >= czero + 10 // checking for correct digit
Chris@102 269 || (dig_value && ( // checking for overflow of ...
Chris@102 270 m_multiplier_overflowed // ... multiplier
Chris@102 271 || static_cast<T>(maxv / dig_value) < m_multiplier // ... subvalue
Chris@102 272 || static_cast<T>(maxv - new_sub_value) < m_value // ... whole expression
Chris@102 273 ))
Chris@102 274 ) return false;
Chris@102 275
Chris@102 276 m_value = static_cast<T>(m_value + new_sub_value);
Chris@102 277
Chris@102 278 return true;
Chris@102 279 }
Chris@102 280
Chris@102 281 bool main_convert_loop() BOOST_NOEXCEPT {
Chris@102 282 for ( ; m_end >= m_begin; --m_end) {
Chris@102 283 if (!main_convert_iteration()) {
Chris@102 284 return false;
Chris@102 285 }
Chris@102 286 }
Chris@102 287
Chris@102 288 return true;
Chris@102 289 }
Chris@102 290 };
Chris@102 291 }
Chris@102 292 } // namespace boost
Chris@102 293
Chris@102 294 #endif // BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP
Chris@102 295