Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 08:18:48

0001 // Copyright Kevlin Henney, 2000-2005.
0002 // Copyright Alexander Nasonov, 2006-2010.
0003 // Copyright Antony Polukhin, 2011-2024.
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 #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 // lcast_put_unsigned
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                 // Check that ulimited group is unreachable:
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; // current group number
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; // suppressing warnings
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 // lcast_ret_unsigned
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                 // GCC when used with flag -std=c++0x may not have std::numeric_limits
0176                 // specializations for __int128 and unsigned __int128 types.
0177                 // Try compilation with -std=gnu++0x or -std=gnu++11.
0178                 //
0179                 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40856
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                 /* According to Programming languages - C++
0210                  * we MUST check for correct grouping
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) ) //|| begin == end ) return false;
0229                         {
0230                             /*
0231                              * According to Programming languages - C++
0232                              * Digit grouping is checked. That is, the positions of discarded
0233                              * separators is examined for consistency with
0234                              * use_facet<numpunct<charT> >(loc ).grouping()
0235                              *
0236                              * BUT what if there is no separators at all and grouping()
0237                              * is not empty? Well, we have no extraced separators, so we
0238                              * won`t check them for consistency. This will allow us to
0239                              * work with "C" locale from other locales
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                 } /*for*/
0249 
0250                 return true;
0251 #endif
0252             }
0253 
0254         private:
0255             // Iteration that does not care about grouping/separators and assumes that all
0256             // input characters are digits
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                 // We must correctly handle situations like `000000000000000000000000000001`.
0271                 // So we take care of overflow only if `dig_value` is not '0'.
0272                 if (*m_end < czero || *m_end >= czero + 10  // checking for correct digit
0273                     || (dig_value && (                      // checking for overflow of ...
0274                         m_multiplier_overflowed                             // ... multiplier
0275                         || static_cast<T>(maxv / dig_value) < m_multiplier  // ... subvalue
0276                         || static_cast<T>(maxv - new_sub_value) < m_value   // ... whole expression
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 } // namespace boost
0297 
0298 #endif // BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP
0299