// // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) // // 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 BEAST_DETAIL_OSTREAM_HPP #define BEAST_DETAIL_OSTREAM_HPP #include #include #include #include #include #include #include namespace beast { namespace detail { template class buffers_helper { Buffers b_; public: explicit buffers_helper(Buffers const& b) : b_(b) { } template friend std::ostream& operator<<(std::ostream& os, buffers_helper const& v); }; template std::ostream& operator<<(std::ostream& os, buffers_helper const& v) { using boost::asio::buffer_cast; using boost::asio::buffer_size; for(auto const& b : v.b_) os.write(buffer_cast(b), buffer_size(b)); return os; } //------------------------------------------------------------------------------ struct basic_streambuf_movable_helper : std::basic_streambuf> { basic_streambuf_movable_helper( basic_streambuf_movable_helper&&) = default; }; using basic_streambuf_movable = std::is_move_constructible; //------------------------------------------------------------------------------ template class ostream_buffer; template class ostream_buffer : public std::basic_streambuf { using int_type = typename std::basic_streambuf::int_type; using traits_type = typename std::basic_streambuf::traits_type; static std::size_t constexpr max_size = 512; DynamicBuffer& buf_; public: ostream_buffer(ostream_buffer&&) = default; ostream_buffer(ostream_buffer const&) = delete; ~ostream_buffer() noexcept { sync(); } explicit ostream_buffer(DynamicBuffer& buf) : buf_(buf) { prepare(); } int_type overflow(int_type ch) override { if(! Traits::eq_int_type(ch, Traits::eof())) { Traits::assign(*this->pptr(), ch); flush(1); prepare(); return ch; } flush(); return traits_type::eof(); } int sync() override { flush(); prepare(); return 0; } private: void prepare() { using boost::asio::buffer_cast; using boost::asio::buffer_size; auto mbs = buf_.prepare( maybe_read_size_helper(buf_, max_size)); auto const mb = *mbs.begin(); auto const p = buffer_cast(mb); this->setp(p, p + buffer_size(mb) / sizeof(CharT) - 1); } void flush(int extra = 0) { buf_.commit( (this->pptr() - this->pbase() + extra) * sizeof(CharT)); } }; // This nonsense is all to work around a glitch in libstdc++ // where std::basic_streambuf copy constructor is private: // https://github.com/gcc-mirror/gcc/blob/gcc-4_8-branch/libstdc%2B%2B-v3/include/std/streambuf#L799 template class ostream_buffer : public std::basic_streambuf { using int_type = typename std::basic_streambuf::int_type; using traits_type = typename std::basic_streambuf::traits_type; static std::size_t constexpr max_size = 512; DynamicBuffer& buf_; public: ostream_buffer(ostream_buffer&&) = delete; ostream_buffer(ostream_buffer const&) = delete; ~ostream_buffer() noexcept { sync(); } explicit ostream_buffer(DynamicBuffer& buf) : buf_(buf) { prepare(); } int_type overflow(int_type ch) override { if(! Traits::eq_int_type(ch, Traits::eof())) { Traits::assign(*this->pptr(), ch); flush(1); prepare(); return ch; } flush(); return traits_type::eof(); } int sync() override { flush(); prepare(); return 0; } private: void prepare() { using boost::asio::buffer_cast; using boost::asio::buffer_size; auto mbs = buf_.prepare( maybe_read_size_helper(buf_, max_size)); auto const mb = *mbs.begin(); auto const p = buffer_cast(mb); this->setp(p, p + buffer_size(mb) / sizeof(CharT) - 1); } void flush(int extra = 0) { buf_.commit( (this->pptr() - this->pbase() + extra) * sizeof(CharT)); } }; //------------------------------------------------------------------------------ template class ostream_helper; template class ostream_helper< DynamicBuffer, CharT, Traits, true> : public std::basic_ostream { ostream_buffer< DynamicBuffer, CharT, Traits, true> osb_; public: explicit ostream_helper(DynamicBuffer& buf); ostream_helper(ostream_helper&& other); }; template ostream_helper:: ostream_helper(DynamicBuffer& buf) : std::basic_ostream( &this->osb_) , osb_(buf) { } template ostream_helper:: ostream_helper( ostream_helper&& other) : std::basic_ostream(&osb_) , osb_(std::move(other.osb_)) { } // This work-around is for libstdc++ versions that // don't have a movable std::basic_streambuf template class ostream_helper_base { protected: std::unique_ptr member; ostream_helper_base( ostream_helper_base&&) = default; explicit ostream_helper_base(T* t) : member(t) { } }; template class ostream_helper< DynamicBuffer, CharT, Traits, false> : private ostream_helper_base> , public std::basic_ostream { public: explicit ostream_helper(DynamicBuffer& buf) : ostream_helper_base>( new ostream_buffer(buf)) , std::basic_ostream(this->member.get()) { } ostream_helper(ostream_helper&& other) : ostream_helper_base>( std::move(other)) , std::basic_ostream(this->member.get()) { } }; } // detail } // beast #endif