From c58a55a512ea45e37c79e1b4dbd44cd9f0b1ae49 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 30 Aug 2013 08:59:59 +0000 Subject: [PATCH] lexical_cast.hpp improvements: more comments, BOOST_NOEXCEPT and `const`; parser_buf moved to boost/detail/basic_pointerbuf.hpp, better formatting and simplified type traits (refs #9046) [SVN r85523] --- include/boost/detail/basic_pointerbuf.hpp | 136 ++++++++++ include/boost/lexical_cast.hpp | 298 +++++++--------------- 2 files changed, 231 insertions(+), 203 deletions(-) create mode 100644 include/boost/detail/basic_pointerbuf.hpp diff --git a/include/boost/detail/basic_pointerbuf.hpp b/include/boost/detail/basic_pointerbuf.hpp new file mode 100644 index 0000000..81ebfe7 --- /dev/null +++ b/include/boost/detail/basic_pointerbuf.hpp @@ -0,0 +1,136 @@ +//----------------------------------------------------------------------------- +// boost detail/templated_streams.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2013 John Maddock, Antony Polukhin +// +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_DETAIL_BASIC_POINTERBUF_HPP +#define BOOST_DETAIL_BASIC_POINTERBUF_HPP + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include "boost/config.hpp" +#include + +namespace boost { namespace detail { + +// +// class basic_pointerbuf: +// acts as a stream buffer which wraps around a pair of pointers: +// +template +class basic_pointerbuf : public BufferT { +protected: + typedef BufferT base_type; + typedef basic_pointerbuf this_type; + typedef typename base_type::int_type int_type; + typedef typename base_type::char_type char_type; + typedef typename base_type::pos_type pos_type; + typedef ::std::streamsize streamsize; + typedef typename base_type::off_type off_type; + +public: + basic_pointerbuf() : base_type() { setbuf(0, 0); } + const charT* getnext() { return this->gptr(); } + +#ifndef BOOST_NO_USING_TEMPLATE + using base_type::pptr; + using base_type::pbase; +#else + charT* pptr() const { return base_type::pptr(); } + charT* pbase() const { return base_type::pbase(); } +#endif + +protected: + base_type* setbuf(char_type* s, streamsize n); + typename this_type::pos_type seekpos(pos_type sp, ::std::ios_base::openmode which); + typename this_type::pos_type seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which); + +private: + basic_pointerbuf& operator=(const basic_pointerbuf&); + basic_pointerbuf(const basic_pointerbuf&); +}; + +template +BufferT* +basic_pointerbuf::setbuf(char_type* s, streamsize n) +{ + this->setg(s, s, s + n); + return this; +} + +template +typename basic_pointerbuf::pos_type +basic_pointerbuf::seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which) +{ + typedef typename boost::int_t::least cast_type; + + if(which & ::std::ios_base::out) + return pos_type(off_type(-1)); + std::ptrdiff_t size = this->egptr() - this->eback(); + std::ptrdiff_t pos = this->gptr() - this->eback(); + charT* g = this->eback(); + switch(static_cast(way)) + { + case ::std::ios_base::beg: + if((off < 0) || (off > size)) + return pos_type(off_type(-1)); + else + this->setg(g, g + off, g + size); + break; + case ::std::ios_base::end: + if((off < 0) || (off > size)) + return pos_type(off_type(-1)); + else + this->setg(g, g + size - off, g + size); + break; + case ::std::ios_base::cur: + { + std::ptrdiff_t newpos = static_cast(pos + off); + if((newpos < 0) || (newpos > size)) + return pos_type(off_type(-1)); + else + this->setg(g, g + newpos, g + size); + break; + } + default: ; + } +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4244) +#endif + return static_cast(this->gptr() - this->eback()); +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +typename basic_pointerbuf::pos_type +basic_pointerbuf::seekpos(pos_type sp, ::std::ios_base::openmode which) +{ + if(which & ::std::ios_base::out) + return pos_type(off_type(-1)); + off_type size = static_cast(this->egptr() - this->eback()); + charT* g = this->eback(); + if(off_type(sp) <= size) + { + this->setg(g, g + off_type(sp), g + size); + } + return pos_type(off_type(-1)); +} + + +}} // namespace boost::detail + +#endif // BOOST_DETAIL_BASIC_POINTERBUF_HPP + diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index a9cb2a2..fae1155 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -158,6 +158,7 @@ namespace boost #include #include #include +#include #ifndef BOOST_NO_CWCHAR # include #endif @@ -490,9 +491,6 @@ namespace boost { struct lcast_src_length { BOOST_STATIC_CONSTANT(std::size_t, value = 1); - // To check coverage, build the test with - // bjam --v2 profile optimization=off - static void check_coverage() {} }; // Helper for integral types. @@ -523,7 +521,6 @@ namespace boost { BOOST_STATIC_CONSTANT(std::size_t, value = 156); BOOST_STATIC_ASSERT(sizeof(Source) * CHAR_BIT <= 256); #endif - static void check_coverage() {} }; #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION @@ -550,8 +547,6 @@ namespace boost { BOOST_STATIC_CONSTANT(std::size_t, value = 5 + lcast_precision::value + 6 ); - - static void check_coverage() {} }; #endif // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION } @@ -889,7 +884,7 @@ namespace boost { if (begin == end) return false; const CharT minus = lcast_char_constants::minus; const CharT plus = lcast_char_constants::plus; - const int inifinity_size = 8; + const int inifinity_size = 8; // == sizeof("infinity") - 1 /* Parsing +/- */ bool const has_minus = (*begin == minus); @@ -897,31 +892,29 @@ namespace boost { ++ begin; } - if( end-begin < 3 ) return false; - if( lc_iequal(begin, lc_nan, lc_NAN, 3) ) - { + if (end - begin < 3) return false; + if (lc_iequal(begin, lc_nan, lc_NAN, 3)) { begin += 3; - if (end != begin) /* It is 'nan(...)' or some bad input*/ - { - if(end-begin<2) return false; // bad input + if (end != begin) { + /* It is 'nan(...)' or some bad input*/ + + if (end - begin < 2) return false; // bad input -- end; - if( *begin != opening_brace || *end != closing_brace) return false; // bad input + if (*begin != opening_brace || *end != closing_brace) return false; // bad input } if( !has_minus ) value = std::numeric_limits::quiet_NaN(); else value = (boost::math::changesign) (std::numeric_limits::quiet_NaN()); return true; - } else - if (( /* 'INF' or 'inf' */ - end-begin==3 - && - lc_iequal(begin, lc_infinity, lc_INFINITY, 3) + } else if ( + ( /* 'INF' or 'inf' */ + end - begin == 3 // 3 == sizeof('inf') - 1 + && lc_iequal(begin, lc_infinity, lc_INFINITY, 3) ) || ( /* 'INFINITY' or 'infinity' */ - end-begin==inifinity_size - && - lc_iequal(begin, lc_infinity, lc_INFINITY, inifinity_size) + end - begin == inifinity_size + && lc_iequal(begin, lc_infinity, lc_INFINITY, inifinity_size) ) ) { @@ -940,10 +933,8 @@ namespace boost { { using namespace std; const CharT minus = lcast_char_constants::minus; - if ( (boost::math::isnan)(value) ) - { - if ( (boost::math::signbit)(value) ) - { + if ((boost::math::isnan)(value)) { + if ((boost::math::signbit)(value)) { *begin = minus; ++ begin; } @@ -951,10 +942,8 @@ namespace boost { memcpy(begin, lc_nan, 3 * sizeof(CharT)); end = begin + 3; return true; - } else if ( (boost::math::isinf)(value) ) - { - if ( (boost::math::signbit)(value) ) - { + } else if ((boost::math::isinf)(value)) { + if ((boost::math::signbit)(value)) { *begin = minus; ++ begin; } @@ -1222,9 +1211,9 @@ namespace boost { } // Exponent found - if ( begin != end && (Traits::eq(*begin, lowercase_e) || Traits::eq(*begin, capital_e)) ) { + if (begin != end && (Traits::eq(*begin, lowercase_e) || Traits::eq(*begin, capital_e))) { ++ begin; - if ( begin == end ) return false; + if (begin == end) return false; bool const exp_has_minus = Traits::eq(*begin, minus); if (exp_has_minus || Traits::eq(*begin, plus)) { @@ -1271,97 +1260,25 @@ namespace boost { #endif } - namespace detail // parser_buf + namespace detail // basic_unlockedbuf { - // - // class parser_buf: // acts as a stream buffer which wraps around a pair of pointers - // - // This class is copied (and slightly changed) from - // boost/regex/v4/cpp_regex_traits.hpp - // Thanks John Maddock for it! (previous version had some - // problems with libc++ and some other STL implementations) - template - class parser_buf : public BufferType { - typedef BufferType base_type; - typedef typename base_type::int_type int_type; - typedef typename base_type::char_type char_type; - typedef typename base_type::pos_type pos_type; - typedef ::std::streamsize streamsize; - typedef typename base_type::off_type off_type; - + // and gives acces to internals + template + class basic_unlockedbuf : public basic_pointerbuf { public: - parser_buf() : base_type() { setbuf(0, 0); } - const charT* getnext() { return this->gptr(); } + typedef basic_pointerbuf base_type; + typedef BOOST_DEDUCED_TYPENAME base_type::streamsize streamsize; + #ifndef BOOST_NO_USING_TEMPLATE using base_type::pptr; using base_type::pbase; + using base_type::setbuf; #else charT* pptr() const { return base_type::pptr(); } charT* pbase() const { return base_type::pbase(); } + BufferType* setbuf(char_type* s, streamsize n) { return base_type::setbuf(s, n); } #endif - base_type* setbuf(char_type* s, streamsize n) { - this->setg(s, s, s + n); - return this; - } - - pos_type seekpos(pos_type sp, ::std::ios_base::openmode which) { - if(which & ::std::ios_base::out) - return pos_type(off_type(-1)); - off_type size = static_cast(this->egptr() - this->eback()); - charT* g = this->eback(); - if(off_type(sp) <= size) - { - this->setg(g, g + off_type(sp), g + size); - } - return pos_type(off_type(-1)); - } - - pos_type seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which) { - typedef typename boost::int_t::least cast_type; - - if(which & ::std::ios_base::out) - return pos_type(off_type(-1)); - std::ptrdiff_t size = this->egptr() - this->eback(); - std::ptrdiff_t pos = this->gptr() - this->eback(); - charT* g = this->eback(); - switch(static_cast(way)) - { - case ::std::ios_base::beg: - if((off < 0) || (off > size)) - return pos_type(off_type(-1)); - else - this->setg(g, g + off, g + size); - break; - case ::std::ios_base::end: - if((off < 0) || (off > size)) - return pos_type(off_type(-1)); - else - this->setg(g, g + size - off, g + size); - break; - case ::std::ios_base::cur: - { - std::ptrdiff_t newpos = static_cast(pos + off); - if((newpos < 0) || (newpos > size)) - return pos_type(off_type(-1)); - else - this->setg(g, g + newpos, g + size); - break; - } - default: ; - } -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4244) -#endif - return static_cast(this->gptr() - this->eback()); -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - } - private: - parser_buf& operator=(const parser_buf&); - parser_buf(const parser_buf&); }; } @@ -1385,10 +1302,10 @@ namespace boost { typedef std::ostrstream out_stream_t; #elif defined(BOOST_NO_STD_LOCALE) typedef std::ostringstream out_stream_t; - typedef parser_buf buffer_t; + typedef basic_unlockedbuf buffer_t; #else typedef std::basic_ostringstream out_stream_t; - typedef parser_buf, CharT> buffer_t; + typedef basic_unlockedbuf, CharT> buffer_t; #endif typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< RequiresStringbuffer, @@ -1581,6 +1498,18 @@ namespace boost { return end > begin; } #endif + template + bool shl_real(T val) { + CharT* tmp_finish = buffer + CharacterBufferSize; + if (put_inf_nan(buffer, tmp_finish, val)) { + finish = tmp_finish; + return true; + } + + bool const result = shl_real_type(val, buffer, tmp_finish); + finish = tmp_finish; + return result; + } /************************************ OPERATORS << ( ... ) ********************************/ public: @@ -1676,22 +1605,6 @@ namespace boost { bool operator<<(const boost::uint128_type& n) { return shl_unsigned(n); } bool operator<<(const boost::int128_type& n) { return shl_signed(n); } #endif - - private: - template - bool shl_real(T val) { - CharT* tmp_finish = buffer + CharacterBufferSize; - if (put_inf_nan(buffer, tmp_finish, val)) { - finish = tmp_finish; - return true; - } - - bool const result = shl_real_type(val, buffer, tmp_finish); - finish = tmp_finish; - return result; - } - - public: bool operator<<(float val) { return shl_real(val); } bool operator<<(double val) { return shl_real(val); } bool operator<<(long double val) { @@ -1746,10 +1659,8 @@ namespace boost { /************************************ HELPER FUNCTIONS FOR OPERATORS >> ( ... ) ********************************/ private: - template - bool shr_unsigned(Type& output) - { + bool shr_unsigned(Type& output) { if (start == finish) return false; CharT const minus = lcast_char_constants::minus; CharT const plus = lcast_char_constants::plus; @@ -1770,8 +1681,7 @@ namespace boost { } template - bool shr_signed(Type& output) - { + bool shr_signed(Type& output) { if (start == finish) return false; CharT const minus = lcast_char_constants::minus; CharT const plus = lcast_char_constants::plus; @@ -1834,7 +1744,8 @@ namespace boost { stream.unsetf(std::ios::skipws); lcast_set_precision(stream, static_cast(0)); - return stream >> output && stream.get() == Traits::eof(); + return (stream >> output) + && (stream.get() == Traits::eof()); #ifndef BOOST_NO_EXCEPTIONS } catch (const ::std::ios_base::failure& /*f*/) { @@ -1844,8 +1755,7 @@ namespace boost { } template - inline bool shr_xchar(T& output) - { + inline bool shr_xchar(T& output) BOOST_NOEXCEPT { BOOST_STATIC_ASSERT_MSG(( sizeof(CharT) == sizeof(T) ), "boost::lexical_cast does not support narrowing of character types." "Use boost::locale instead" ); @@ -1858,6 +1768,19 @@ namespace boost { return ok; } + template + bool shr_std_array(ArrayT& output) BOOST_NOEXCEPT { + using namespace std; + const std::size_t size = finish - start; + if (size > N - 1) { // `-1` because we need to store \0 at the end + return false; + } + + memcpy(&output[0], start, size * sizeof(CharT)); + output[size] = Traits::to_char_type(0); + return true; + } + /************************************ OPERATORS >> ( ... ) ********************************/ public: bool operator>>(unsigned short& output) { return shr_unsigned(output); } @@ -1892,98 +1815,68 @@ namespace boost { bool operator>>(char32_t& output) { return shr_xchar(output); } #endif template - bool operator>>(std::basic_string& str) { str.assign(start, finish); return true; } - - template - bool operator>>(boost::container::basic_string& str) { str.assign(start, finish); return true; } - - - private: - template - bool shr_std_array(ArrayT& output) BOOST_NOEXCEPT - { - using namespace std; - const std::size_t size = finish - start; - if (size > N - 1) { // `-1` because we need to store \0 at the end - return false; - } - - memcpy(&output[0], start, size * sizeof(CharT)); - output[size] = Traits::to_char_type(0); - return true; + bool operator>>(std::basic_string& str) { + str.assign(start, finish); return true; } - public: + template + bool operator>>(boost::container::basic_string& str) { + str.assign(start, finish); return true; + } template - bool operator>>(boost::array& output) BOOST_NOEXCEPT - { + bool operator>>(boost::array& output) BOOST_NOEXCEPT { return shr_std_array(output); } template - bool operator>>(boost::array& output) - { + bool operator>>(boost::array& output) BOOST_NOEXCEPT { return ((*this) >> reinterpret_cast& >(output)); } template - bool operator>>(boost::array& output) - { + bool operator>>(boost::array& output) BOOST_NOEXCEPT { return ((*this) >> reinterpret_cast& >(output)); } #ifndef BOOST_NO_CXX11_HDR_ARRAY - template - bool operator>>(std::array& output) BOOST_NOEXCEPT - { - return shr_std_array(output); - } - - template - bool operator>>(std::array& output) - { - return ((*this) >> reinterpret_cast& >(output)); - } - - template - bool operator>>(std::array& output) - { - return ((*this) >> reinterpret_cast& >(output)); + template + bool operator>>(std::array& output) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG( + (sizeof(boost::array) == sizeof(boost::array)), + "std::array and boost::array must have exactly the same layout." + ); + return ((*this) >> reinterpret_cast& >(input)); } #endif - /* * case "-0" || "0" || "+0" : output = false; return true; * case "1" || "+1": output = true; return true; * default: return false; */ - bool operator>>(bool& output) BOOST_NOEXCEPT - { + bool operator>>(bool& output) BOOST_NOEXCEPT { CharT const zero = lcast_char_constants::zero; CharT const plus = lcast_char_constants::plus; CharT const minus = lcast_char_constants::minus; - switch(finish-start) - { + output = false; // Suppress warning about uninitalized variable + switch (finish - start) { case 1: output = Traits::eq(start[0], zero+1); return output || Traits::eq(start[0], zero ); + case 2: - if ( Traits::eq( plus, *start) ) - { + if (Traits::eq(plus, *start)) { ++start; - output = Traits::eq(start[0], zero +1); + output = Traits::eq(start[0], zero + 1); return output || Traits::eq(start[0], zero ); - } else - { - output = false; + } else { return Traits::eq( minus, *start) && Traits::eq( zero, start[1]); } + default: - output = false; // Suppress warning about uninitalized variable return false; } } @@ -1995,7 +1888,7 @@ namespace boost { template bool float_types_converter_internal(T& output, int /*tag*/) { if (parse_inf_nan(start, finish, output)) return true; - bool return_value = shr_using_base_class(output); + bool const return_value = shr_using_base_class(output); /* Some compilers and libraries successfully * parse 'inf', 'INFINITY', '1.0E', '1.0E-'... @@ -2020,13 +1913,12 @@ namespace boost { } // Optimised converter - bool float_types_converter_internal(double& output,char /*tag*/) { - return lcast_ret_float(output,start,finish); + bool float_types_converter_internal(double& output, char /*tag*/) { + return lcast_ret_float(output, start, finish); } public: - bool operator>>(double& output) - { + bool operator>>(double& output) { /* * Some compilers implement long double as double. In that case these types have * same size, same precision, same max and min values... And it means, @@ -2046,16 +1938,17 @@ namespace boost { return float_types_converter_internal(output, tag); } - bool operator>>(long double& output) - { + bool operator>>(long double& output) { int tag = 0; return float_types_converter_internal(output, tag); } // Generic istream-based algorithm. // lcast_streambuf_for_target::value is true. - template - bool operator>>(InputStreamable& output) { return shr_using_base_class(output); } + template + bool operator>>(InputStreamable& output) { + return shr_using_base_class(output); + } }; } @@ -2153,7 +2046,6 @@ namespace boost { Target result; interpreter_type interpreter; - stream_trait::len_t::check_coverage(); // Disabling ADL, by directly specifying operators. if(!(interpreter.operator <<(arg) && interpreter.operator >>(result)))