| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 | // Copyright (c) 2009-2016 Vladimir Batov.// Use, modification and distribution are subject to the Boost Software License,// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.#ifndef BOOST_CONVERT_STRINGSTREAM_BASED_CONVERTER_HPP#define BOOST_CONVERT_STRINGSTREAM_BASED_CONVERTER_HPP#include <boost/convert/parameters.hpp>#include <boost/convert/detail/is_string.hpp>#include <boost/make_default.hpp>#include <boost/noncopyable.hpp>#include <sstream>#include <iomanip>#define BOOST_CNV_STRING_ENABLE                                         \    template<typename string_type, typename type>                       \    typename boost::enable_if<cnv::is_string<string_type>, void>::type  \    operator()#define BOOST_CNV_PARAM(PARAM_NAME, PARAM_TYPE) \    this_type&                                  \    operator()(boost::parameter::aux::tag<boost::cnv::parameter::type::PARAM_NAME, PARAM_TYPE const>::type const& arg)namespace boost { namespace cnv{    template<class Char> struct basic_stream;    using cstream = boost::cnv::basic_stream<char>;    using wstream = boost::cnv::basic_stream<wchar_t>;}}template<class Char>struct boost::cnv::basic_stream : boost::noncopyable{    // C01. In string-to-type conversions the "string" must be a CONTIGUOUS ARRAY of    //      characters because "ibuffer_type" uses/relies on that (it deals with char_type*).    // C02. Use the provided "string_in" as the input (read-from) buffer and, consequently,    //      avoid the overhead associated with stream_.str(string_in) --    //      copying of the content into internal buffer.    // C03. The "strbuf.gptr() != strbuf.egptr()" check replaces "istream.eof() != true"    //      which for some reason does not work when we try converting the "true" string    //      to "bool" with std::boolalpha set. Seems that istream state gets unsynced compared    //      to the actual underlying buffer.    using        char_type = Char;    using        this_type = boost::cnv::basic_stream<char_type>;    using      stream_type = std::basic_stringstream<char_type>;    using     istream_type = std::basic_istream<char_type>;    using      buffer_type = std::basic_streambuf<char_type>;    using      stdstr_type = std::basic_string<char_type>;    using manipulator_type = std::ios_base& (*)(std::ios_base&);    struct ibuffer_type : buffer_type    {        using buffer_type::eback;        using buffer_type::gptr;        using buffer_type::egptr;        ibuffer_type(char_type const* beg, std::size_t sz) //C01        {            char_type* b = const_cast<char_type*>(beg);            buffer_type::setg(b, b, b + sz);        }    };    struct obuffer_type : buffer_type    {        using buffer_type::pbase;        using buffer_type::pptr;        using buffer_type::epptr;    };    basic_stream() : stream_(std::ios_base::in | std::ios_base::out) {}#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )    basic_stream(this_type&& other) : stream_(std::move(other.stream_)) {}#endif    BOOST_CNV_STRING_ENABLE(type const& v, optional<string_type>& s) const { to_str(v, s); }    BOOST_CNV_STRING_ENABLE(string_type const& s, optional<type>& r) const { str_to(cnv::range<string_type const>(s), r); }    // Resolve ambiguity of string-to-string    template<typename type> void operator()(  char_type const* s, optional<type>& r) const { str_to(cnv::range< char_type const*>(s), r); }    template<typename type> void operator()(stdstr_type const& s, optional<type>& r) const { str_to(cnv::range<stdstr_type const>(s), r); }    // Formatters    template<typename manipulator>    this_type& operator() (manipulator m) { return (stream_ << m, *this); }    this_type& operator() (manipulator_type m) { return (m(stream_), *this); }    this_type& operator() (std::locale const& l) { return (stream_.imbue(l), *this); }    BOOST_CNV_PARAM(locale, std::locale) { return (stream_.imbue(arg[cnv::parameter::locale]), *this); }    BOOST_CNV_PARAM(precision,      int) { return (stream_.precision(arg[cnv::parameter::precision]), *this); }    BOOST_CNV_PARAM(width,          int) { return (stream_.width(arg[cnv::parameter::width]), *this); }    BOOST_CNV_PARAM(fill,          char) { return (stream_.fill(arg[cnv::parameter::fill]), *this); }    BOOST_CNV_PARAM(uppercase,     bool)    {        bool uppercase = arg[cnv::parameter::uppercase];        uppercase ? (void) stream_.setf(std::ios::uppercase) : stream_.unsetf(std::ios::uppercase);        return *this;    }    BOOST_CNV_PARAM(skipws, bool)    {        bool skipws = arg[cnv::parameter::skipws];        skipws ? (void) stream_.setf(std::ios::skipws) : stream_.unsetf(std::ios::skipws);        return *this;    }    BOOST_CNV_PARAM(adjust, boost::cnv::adjust)    {        cnv::adjust adjust = arg[cnv::parameter::adjust];        /**/ if (adjust == cnv::adjust:: left) stream_.setf(std::ios::adjustfield, std::ios:: left);        else if (adjust == cnv::adjust::right) stream_.setf(std::ios::adjustfield, std::ios::right);        else BOOST_ASSERT(!"Not implemented");        return *this;    }    BOOST_CNV_PARAM(base, boost::cnv::base)    {        cnv::base base = arg[cnv::parameter::base];        /**/ if (base == cnv::base::dec) std::dec(stream_);        else if (base == cnv::base::hex) std::hex(stream_);        else if (base == cnv::base::oct) std::oct(stream_);        else BOOST_ASSERT(!"Not implemented");        return *this;    }    BOOST_CNV_PARAM(notation, boost::cnv::notation)    {        cnv::notation notation = arg[cnv::parameter::notation];        /**/ if (notation == cnv::notation::     fixed)      std::fixed(stream_);        else if (notation == cnv::notation::scientific) std::scientific(stream_);        else BOOST_ASSERT(!"Not implemented");        return *this;    }    private:    template<typename string_type, typename out_type> void str_to(cnv::range<string_type>, optional<out_type>&) const;    template<typename string_type, typename  in_type> void to_str(in_type const&, optional<string_type>&) const;    mutable stream_type stream_;};template<typename char_type>template<typename string_type, typename in_type>inlinevoidboost::cnv::basic_stream<char_type>::to_str(    in_type const& value_in,    boost::optional<string_type>& string_out) const{    stream_.clear();            // Clear the flags    stream_.str(stdstr_type()); // Clear/empty the content of the stream    if (!(stream_ << value_in).fail())    {        buffer_type*     buf = stream_.rdbuf();        obuffer_type*   obuf = reinterpret_cast<obuffer_type*>(buf);        char_type const* beg = obuf->pbase();        char_type const* end = obuf->pptr();        string_out = string_type(beg, end); // Instead of stream_.str();    }}template<typename char_type>template<typename string_type, typename out_type>inlinevoidboost::cnv::basic_stream<char_type>::str_to(    boost::cnv::range<string_type> string_in,    boost::optional<out_type>& result_out) const{    if (string_in.empty ()) return;    istream_type& istream = stream_;    buffer_type*   oldbuf = istream.rdbuf();    char_type const*  beg = &*string_in.begin();    std::size_t        sz = string_in.end() - string_in.begin();    ibuffer_type   newbuf (beg, sz); //C02    istream.rdbuf(&newbuf);    istream.clear(); // Clear the flags    istream >> *(result_out = boost::make_default<out_type>());    if (istream.fail() || newbuf.gptr() != newbuf.egptr()/*C03*/)        result_out = boost::none;    istream.rdbuf(oldbuf);}#undef BOOST_CNV_STRING_ENABLE#undef BOOST_CNV_PARAM#endif // BOOST_CONVERT_STRINGSTREAM_BASED_CONVERTER_HPP
 |