Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:13

0001 // Copyright Kevlin Henney, 2000-2005.
0002 // Copyright Alexander Nasonov, 2006-2010.
0003 // Copyright Antony Polukhin, 2011-2023.
0004 //
0005 // Distributed under the Boost Software License, Version 1.0. (See
0006 // accompanying file LICENSE_1_0.txt or copy at
0007 // http://www.boost.org/LICENSE_1_0.txt)
0008 //
0009 // what:  lexical_cast custom keyword cast
0010 // who:   contributed by Kevlin Henney,
0011 //        enhanced with contributions from Terje Slettebo,
0012 //        with additional fixes and suggestions from Gennaro Prota,
0013 //        Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov,
0014 //        Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann,
0015 //        Cheng Yang, Matthew Bradbury, David W. Birdsall, Pavel Korzh and other Boosters
0016 // when:  November 2000, March 2003, June 2005, June 2006, March 2011 - 2014
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         // Getting error at this point means, that your STL library is old/lame/misconfigured.
0041         // If nothing can be done with STL library, define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE,
0042         // but beware: lexical_cast will understand only 'C' locale delimeters and thousands
0043         // separators.
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 // lcast_to_unsigned
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 // lcast_put_unsigned
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                 // Check that ulimited group is unreachable:
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; // current group number
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; // suppressing warnings
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 // lcast_ret_unsigned
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                 // GCC when used with flag -std=c++0x may not have std::numeric_limits
0173                 // specializations for __int128 and unsigned __int128 types.
0174                 // Try compilation with -std=gnu++0x or -std=gnu++11.
0175                 //
0176                 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40856
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                 /* According to Programming languages - C++
0207                  * we MUST check for correct grouping
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) ) //|| begin == end ) return false;
0226                         {
0227                             /*
0228                              * According to Programming languages - C++
0229                              * Digit grouping is checked. That is, the positions of discarded
0230                              * separators is examined for consistency with
0231                              * use_facet<numpunct<charT> >(loc ).grouping()
0232                              *
0233                              * BUT what if there is no separators at all and grouping()
0234                              * is not empty? Well, we have no extraced separators, so we
0235                              * won`t check them for consistency. This will allow us to
0236                              * work with "C" locale from other locales
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                 } /*for*/
0246 
0247                 return true;
0248 #endif
0249             }
0250 
0251         private:
0252             // Iteration that does not care about grouping/separators and assumes that all
0253             // input characters are digits
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                 // We must correctly handle situations like `000000000000000000000000000001`.
0265                 // So we take care of overflow only if `dig_value` is not '0'.
0266                 if (*m_end < czero || *m_end >= czero + 10  // checking for correct digit
0267                     || (dig_value && (                      // checking for overflow of ...
0268                         m_multiplier_overflowed                             // ... multiplier
0269                         || static_cast<T>(maxv / dig_value) < m_multiplier  // ... subvalue
0270                         || static_cast<T>(maxv - new_sub_value) < m_value   // ... whole expression
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 } // namespace boost
0291 
0292 #endif // BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP
0293