Chris@102: // Copyright Kevlin Henney, 2000-2005. Chris@102: // Copyright Alexander Nasonov, 2006-2010. Chris@102: // Copyright Antony Polukhin, 2011-2014. Chris@102: // Chris@102: // Distributed under the Boost Software License, Version 1.0. (See Chris@102: // accompanying file LICENSE_1_0.txt or copy at Chris@102: // http://www.boost.org/LICENSE_1_0.txt) Chris@102: // Chris@102: // what: lexical_cast custom keyword cast Chris@102: // who: contributed by Kevlin Henney, Chris@102: // enhanced with contributions from Terje Slettebo, Chris@102: // with additional fixes and suggestions from Gennaro Prota, Chris@102: // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov, Chris@102: // Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann, Chris@102: // Cheng Yang, Matthew Bradbury, David W. Birdsall, Pavel Korzh and other Boosters Chris@102: // when: November 2000, March 2003, June 2005, June 2006, March 2011 - 2014 Chris@102: Chris@102: #ifndef BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP Chris@102: #define BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP Chris@102: Chris@102: #include Chris@102: #ifdef BOOST_HAS_PRAGMA_ONCE Chris@102: # pragma once Chris@102: #endif Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: Chris@102: #ifndef BOOST_NO_STD_LOCALE Chris@102: # include Chris@102: #else Chris@102: # ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE Chris@102: // Getting error at this point means, that your STL library is old/lame/misconfigured. Chris@102: // If nothing can be done with STL library, define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE, Chris@102: // but beware: lexical_cast will understand only 'C' locale delimeters and thousands Chris@102: // separators. Chris@102: # error "Unable to use header. Define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE to force " Chris@102: # error "boost::lexical_cast to use only 'C' locale during conversions." Chris@102: # endif Chris@102: #endif Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: namespace boost Chris@102: { Chris@102: namespace detail // lcast_to_unsigned Chris@102: { Chris@102: template Chris@102: inline Chris@102: BOOST_DEDUCED_TYPENAME boost::make_unsigned::type lcast_to_unsigned(const T value) BOOST_NOEXCEPT { Chris@102: typedef BOOST_DEDUCED_TYPENAME boost::make_unsigned::type result_type; Chris@102: return value < 0 Chris@102: ? static_cast(0u - static_cast(value)) Chris@102: : static_cast(value); Chris@102: } Chris@102: } Chris@102: Chris@102: namespace detail // lcast_put_unsigned Chris@102: { Chris@102: template Chris@102: class lcast_put_unsigned: boost::noncopyable { Chris@102: typedef BOOST_DEDUCED_TYPENAME Traits::int_type int_type; Chris@102: BOOST_DEDUCED_TYPENAME boost::mpl::if_c< Chris@102: (sizeof(int_type) > sizeof(T)) Chris@102: , int_type Chris@102: , T Chris@102: >::type m_value; Chris@102: CharT* m_finish; Chris@102: CharT const m_czero; Chris@102: int_type const m_zero; Chris@102: Chris@102: public: Chris@102: lcast_put_unsigned(const T n_param, CharT* finish) BOOST_NOEXCEPT Chris@102: : m_value(n_param), m_finish(finish) Chris@102: , m_czero(lcast_char_constants::zero), m_zero(Traits::to_int_type(m_czero)) Chris@102: { Chris@102: #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS Chris@102: BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); Chris@102: #endif Chris@102: } Chris@102: Chris@102: CharT* convert() { Chris@102: #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE Chris@102: std::locale loc; Chris@102: if (loc == std::locale::classic()) { Chris@102: return main_convert_loop(); Chris@102: } Chris@102: Chris@102: typedef std::numpunct numpunct; Chris@102: numpunct const& np = BOOST_USE_FACET(numpunct, loc); Chris@102: std::string const grouping = np.grouping(); Chris@102: std::string::size_type const grouping_size = grouping.size(); Chris@102: Chris@102: if (!grouping_size || grouping[0] <= 0) { Chris@102: return main_convert_loop(); Chris@102: } Chris@102: Chris@102: #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS Chris@102: // Check that ulimited group is unreachable: Chris@102: BOOST_STATIC_ASSERT(std::numeric_limits::digits10 < CHAR_MAX); Chris@102: #endif Chris@102: CharT const thousands_sep = np.thousands_sep(); Chris@102: std::string::size_type group = 0; // current group number Chris@102: char last_grp_size = grouping[0]; Chris@102: char left = last_grp_size; Chris@102: Chris@102: do { Chris@102: if (left == 0) { Chris@102: ++group; Chris@102: if (group < grouping_size) { Chris@102: char const grp_size = grouping[group]; Chris@102: last_grp_size = (grp_size <= 0 ? static_cast(CHAR_MAX) : grp_size); Chris@102: } Chris@102: Chris@102: left = last_grp_size; Chris@102: --m_finish; Chris@102: Traits::assign(*m_finish, thousands_sep); Chris@102: } Chris@102: Chris@102: --left; Chris@102: } while (main_convert_iteration()); Chris@102: Chris@102: return m_finish; Chris@102: #else Chris@102: return main_convert_loop(); Chris@102: #endif Chris@102: } Chris@102: Chris@102: private: Chris@102: inline bool main_convert_iteration() BOOST_NOEXCEPT { Chris@102: --m_finish; Chris@102: int_type const digit = static_cast(m_value % 10U); Chris@102: Traits::assign(*m_finish, Traits::to_char_type(m_zero + digit)); Chris@102: m_value /= 10; Chris@102: return !!m_value; // suppressing warnings Chris@102: } Chris@102: Chris@102: inline CharT* main_convert_loop() BOOST_NOEXCEPT { Chris@102: while (main_convert_iteration()); Chris@102: return m_finish; Chris@102: } Chris@102: }; Chris@102: } Chris@102: Chris@102: namespace detail // lcast_ret_unsigned Chris@102: { Chris@102: template Chris@102: class lcast_ret_unsigned: boost::noncopyable { Chris@102: bool m_multiplier_overflowed; Chris@102: T m_multiplier; Chris@102: T& m_value; Chris@102: const CharT* const m_begin; Chris@102: const CharT* m_end; Chris@102: Chris@102: public: Chris@102: lcast_ret_unsigned(T& value, const CharT* const begin, const CharT* end) BOOST_NOEXCEPT Chris@102: : m_multiplier_overflowed(false), m_multiplier(1), m_value(value), m_begin(begin), m_end(end) Chris@102: { Chris@102: #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS Chris@102: BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); Chris@102: Chris@102: // GCC when used with flag -std=c++0x may not have std::numeric_limits Chris@102: // specializations for __int128 and unsigned __int128 types. Chris@102: // Try compilation with -std=gnu++0x or -std=gnu++11. Chris@102: // Chris@102: // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40856 Chris@102: BOOST_STATIC_ASSERT_MSG(std::numeric_limits::is_specialized, Chris@102: "std::numeric_limits are not specialized for integral type passed to boost::lexical_cast" Chris@102: ); Chris@102: #endif Chris@102: } Chris@102: Chris@102: inline bool convert() { Chris@102: CharT const czero = lcast_char_constants::zero; Chris@102: --m_end; Chris@102: m_value = static_cast(0); Chris@102: Chris@102: if (m_begin > m_end || *m_end < czero || *m_end >= czero + 10) Chris@102: return false; Chris@102: m_value = static_cast(*m_end - czero); Chris@102: --m_end; Chris@102: Chris@102: #ifdef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE Chris@102: return main_convert_loop(); Chris@102: #else Chris@102: std::locale loc; Chris@102: if (loc == std::locale::classic()) { Chris@102: return main_convert_loop(); Chris@102: } Chris@102: Chris@102: typedef std::numpunct numpunct; Chris@102: numpunct const& np = BOOST_USE_FACET(numpunct, loc); Chris@102: std::string const& grouping = np.grouping(); Chris@102: std::string::size_type const grouping_size = grouping.size(); Chris@102: Chris@102: /* According to Programming languages - C++ Chris@102: * we MUST check for correct grouping Chris@102: */ Chris@102: if (!grouping_size || grouping[0] <= 0) { Chris@102: return main_convert_loop(); Chris@102: } Chris@102: Chris@102: unsigned char current_grouping = 0; Chris@102: CharT const thousands_sep = np.thousands_sep(); Chris@102: char remained = static_cast(grouping[current_grouping] - 1); Chris@102: Chris@102: for (;m_end >= m_begin; --m_end) Chris@102: { Chris@102: if (remained) { Chris@102: if (!main_convert_iteration()) { Chris@102: return false; Chris@102: } Chris@102: --remained; Chris@102: } else { Chris@102: if ( !Traits::eq(*m_end, thousands_sep) ) //|| begin == end ) return false; Chris@102: { Chris@102: /* Chris@102: * According to Programming languages - C++ Chris@102: * Digit grouping is checked. That is, the positions of discarded Chris@102: * separators is examined for consistency with Chris@102: * use_facet >(loc ).grouping() Chris@102: * Chris@102: * BUT what if there is no separators at all and grouping() Chris@102: * is not empty? Well, we have no extraced separators, so we Chris@102: * won`t check them for consistency. This will allow us to Chris@102: * work with "C" locale from other locales Chris@102: */ Chris@102: return main_convert_loop(); Chris@102: } else { Chris@102: if (m_begin == m_end) return false; Chris@102: if (current_grouping < grouping_size - 1) ++current_grouping; Chris@102: remained = grouping[current_grouping]; Chris@102: } Chris@102: } Chris@102: } /*for*/ Chris@102: Chris@102: return true; Chris@102: #endif Chris@102: } Chris@102: Chris@102: private: Chris@102: // Iteration that does not care about grouping/separators and assumes that all Chris@102: // input characters are digits Chris@102: inline bool main_convert_iteration() BOOST_NOEXCEPT { Chris@102: CharT const czero = lcast_char_constants::zero; Chris@102: T const maxv = (std::numeric_limits::max)(); Chris@102: Chris@102: m_multiplier_overflowed = m_multiplier_overflowed || (maxv/10 < m_multiplier); Chris@102: m_multiplier = static_cast(m_multiplier * 10); Chris@102: Chris@102: T const dig_value = static_cast(*m_end - czero); Chris@102: T const new_sub_value = static_cast(m_multiplier * dig_value); Chris@102: Chris@102: // We must correctly handle situations like `000000000000000000000000000001`. Chris@102: // So we take care of overflow only if `dig_value` is not '0'. Chris@102: if (*m_end < czero || *m_end >= czero + 10 // checking for correct digit Chris@102: || (dig_value && ( // checking for overflow of ... Chris@102: m_multiplier_overflowed // ... multiplier Chris@102: || static_cast(maxv / dig_value) < m_multiplier // ... subvalue Chris@102: || static_cast(maxv - new_sub_value) < m_value // ... whole expression Chris@102: )) Chris@102: ) return false; Chris@102: Chris@102: m_value = static_cast(m_value + new_sub_value); Chris@102: Chris@102: return true; Chris@102: } Chris@102: Chris@102: bool main_convert_loop() BOOST_NOEXCEPT { Chris@102: for ( ; m_end >= m_begin; --m_end) { Chris@102: if (!main_convert_iteration()) { Chris@102: return false; Chris@102: } Chris@102: } Chris@102: Chris@102: return true; Chris@102: } Chris@102: }; Chris@102: } Chris@102: } // namespace boost Chris@102: Chris@102: #endif // BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP Chris@102: