ostream workaround for gcc 4.8.4

This commit is contained in:
Vinnie Falco
2017-05-08 19:02:58 -07:00
parent 5c9e6c0fc0
commit 140bf5cb1d
2 changed files with 175 additions and 101 deletions

View File

@@ -9,7 +9,6 @@
#define BEAST_DETAIL_OSTREAM_HPP #define BEAST_DETAIL_OSTREAM_HPP
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/utility/base_from_member.hpp>
#include <memory> #include <memory>
#include <ostream> #include <ostream>
#include <streambuf> #include <streambuf>
@@ -53,9 +52,29 @@ operator<<(std::ostream& os,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template< struct basic_streambuf_movable_helper :
class DynamicBuffer, class CharT, class Traits> std::basic_streambuf<char, std::char_traits<char>>
{
basic_streambuf_movable_helper(
basic_streambuf_movable_helper&&) = default;
};
using basic_streambuf_movable =
#if 0
std::is_move_constructible<basic_streambuf_movable_helper>;
#else
std::false_type;
#endif
//------------------------------------------------------------------------------
template<class DynamicBuffer,
class CharT, class Traits, bool isMovable>
class ostream_buffer;
template<class DynamicBuffer, class CharT, class Traits>
class ostream_buffer class ostream_buffer
<DynamicBuffer, CharT, Traits, true>
: public std::basic_streambuf<CharT, Traits> : public std::basic_streambuf<CharT, Traits>
{ {
using int_type = typename using int_type = typename
@@ -72,91 +91,142 @@ public:
ostream_buffer(ostream_buffer&&) = default; ostream_buffer(ostream_buffer&&) = default;
ostream_buffer(ostream_buffer const&) = delete; ostream_buffer(ostream_buffer const&) = delete;
~ostream_buffer() noexcept; ~ostream_buffer() noexcept
{
sync();
}
explicit explicit
ostream_buffer(DynamicBuffer& buf); ostream_buffer(DynamicBuffer& buf)
: buf_(buf)
{
prepare();
}
int_type int_type
overflow(int_type ch) override; 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 int
sync() override; sync() override
{
flush();
prepare();
return 0;
}
private: private:
void void
prepare(); prepare()
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
auto mbs = buf_.prepare(
read_size_helper(buf_, max_size));
auto const mb = *mbs.begin();
auto const p = buffer_cast<CharT*>(mb);
this->setp(p,
p + buffer_size(mb) / sizeof(CharT) - 1);
}
void void
flush(int extra = 0); flush(int extra = 0)
{
buf_.commit(
(this->pptr() - this->pbase() + extra) *
sizeof(CharT));
}
}; };
template<class DynamicBuffer, class CharT, class Traits> // This nonsense is all to work around a glitch in libstdc++
ostream_buffer<DynamicBuffer, CharT, Traits>:: // where std::basic_streambuf copy constructor is private:
~ostream_buffer() noexcept // https://github.com/gcc-mirror/gcc/blob/gcc-4_8-branch/libstdc%2B%2B-v3/include/std/streambuf#L799
{
sync();
}
template<class DynamicBuffer, class CharT, class Traits> template<class DynamicBuffer, class CharT, class Traits>
ostream_buffer<DynamicBuffer, CharT, Traits>:: class ostream_buffer
ostream_buffer(DynamicBuffer& buf) <DynamicBuffer, CharT, Traits, false>
: buf_(buf) : public std::basic_streambuf<CharT, Traits>
{ {
prepare(); using int_type = typename
} std::basic_streambuf<CharT, Traits>::int_type;
template<class DynamicBuffer, class CharT, class Traits> using traits_type = typename
auto std::basic_streambuf<CharT, Traits>::traits_type;
ostream_buffer<DynamicBuffer, CharT, Traits>::
overflow(int_type ch) -> static std::size_t constexpr max_size = 512;
int_type
{ DynamicBuffer& buf_;
if(! Traits::eq_int_type(ch, Traits::eof()))
public:
ostream_buffer(ostream_buffer&&) = delete;
ostream_buffer(ostream_buffer const&) = delete;
~ostream_buffer() noexcept
{ {
Traits::assign(*this->pptr(), ch); sync();
flush(1);
prepare();
return ch;
} }
flush();
return traits_type::eof();
}
template<class DynamicBuffer, class CharT, class Traits> explicit
int ostream_buffer(DynamicBuffer& buf)
ostream_buffer<DynamicBuffer, CharT, Traits>:: : buf_(buf)
sync() {
{ prepare();
flush(); }
prepare();
return 0;
}
template<class DynamicBuffer, class CharT, class Traits> int_type
void overflow(int_type ch) override
ostream_buffer<DynamicBuffer, CharT, Traits>:: {
prepare() if(! Traits::eq_int_type(ch, Traits::eof()))
{ {
using boost::asio::buffer_cast; Traits::assign(*this->pptr(), ch);
using boost::asio::buffer_size; flush(1);
auto mbs = buf_.prepare( prepare();
read_size_helper(buf_, max_size)); return ch;
auto const mb = *mbs.begin(); }
auto const p = buffer_cast<CharT*>(mb); flush();
this->setp(p, return traits_type::eof();
p + buffer_size(mb) / sizeof(CharT) - 1); }
}
template<class DynamicBuffer, class CharT, class Traits> int
void sync() override
ostream_buffer<DynamicBuffer, CharT, Traits>:: {
flush(int extra) flush();
{ prepare();
buf_.commit( return 0;
(this->pptr() - this->pbase() + extra) * }
sizeof(CharT));
} private:
void
prepare()
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
auto mbs = buf_.prepare(
read_size_helper(buf_, max_size));
auto const mb = *mbs.begin();
auto const p = buffer_cast<CharT*>(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));
}
};
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -169,7 +239,8 @@ class ostream_helper<
DynamicBuffer, CharT, Traits, true> DynamicBuffer, CharT, Traits, true>
: public std::basic_ostream<CharT, Traits> : public std::basic_ostream<CharT, Traits>
{ {
ostream_buffer<DynamicBuffer, CharT, Traits> osb_; ostream_buffer<
DynamicBuffer, CharT, Traits, true> osb_;
public: public:
explicit explicit
@@ -199,41 +270,48 @@ ostream_helper(
// This work-around is for libstdc++ versions that // This work-around is for libstdc++ versions that
// don't have a movable std::basic_streambuf // don't have a movable std::basic_streambuf
template<class DynamicBuffer, class CharT, class Traits> template<class T>
struct ostream_helper< class ostream_helper_base
DynamicBuffer, CharT, Traits, false>
: private boost::base_from_member<
std::unique_ptr<ostream_buffer<
DynamicBuffer, CharT, Traits>>>
, std::basic_ostream<CharT, Traits>
{ {
explicit protected:
ostream_helper(DynamicBuffer& buf); std::unique_ptr<T> member;
ostream_helper(ostream_helper&& other); ostream_helper_base(
ostream_helper_base&&) = default;
explicit
ostream_helper_base(T* t)
: member(t)
{
}
}; };
template<class DynamicBuffer, class CharT, class Traits> template<class DynamicBuffer, class CharT, class Traits>
ostream_helper<DynamicBuffer, CharT, Traits, false>:: class ostream_helper<
ostream_helper(DynamicBuffer& buf) DynamicBuffer, CharT, Traits, false>
: boost::base_from_member<std::unique_ptr< : private ostream_helper_base<ostream_buffer<
ostream_buffer<DynamicBuffer, CharT, Traits>>>( DynamicBuffer, CharT, Traits, false>>
new ostream_buffer<DynamicBuffer, CharT, Traits>(buf)) , public std::basic_ostream<CharT, Traits>
, std::basic_ostream<CharT, Traits>(
this->member.get())
{ {
} public:
explicit
ostream_helper(DynamicBuffer& buf)
: ostream_helper_base<ostream_buffer<
DynamicBuffer, CharT, Traits, false>>(
new ostream_buffer<DynamicBuffer,
CharT, Traits, false>(buf))
, std::basic_ostream<CharT, Traits>(this->member.get())
{
}
template<class DynamicBuffer, class CharT, class Traits> ostream_helper(ostream_helper&& other)
ostream_helper<DynamicBuffer, CharT, Traits, false>:: : ostream_helper_base<ostream_buffer<
ostream_helper(ostream_helper&& other) DynamicBuffer, CharT, Traits, false>>(
: boost::base_from_member<std::unique_ptr< std::move(other))
ostream_buffer<DynamicBuffer, CharT, Traits>>>( , std::basic_ostream<CharT, Traits>(this->member.get())
std::move(other.member)) {
, std::basic_ostream<CharT, Traits>( }
this->member.get()) };
{
}
} // detail } // detail
} // beast } // beast

View File

@@ -80,9 +80,7 @@ implementation_defined
#else #else
detail::ostream_helper< detail::ostream_helper<
DynamicBuffer, char, std::char_traits<char>, DynamicBuffer, char, std::char_traits<char>,
std::is_move_constructible< detail::basic_streambuf_movable::value>
detail::ostream_buffer<DynamicBuffer,
char, std::char_traits<char>>>::value>
#endif #endif
ostream(DynamicBuffer& buffer) ostream(DynamicBuffer& buffer)
{ {
@@ -90,9 +88,7 @@ ostream(DynamicBuffer& buffer)
"DynamicBuffer requirements not met"); "DynamicBuffer requirements not met");
return detail::ostream_helper< return detail::ostream_helper<
DynamicBuffer, char, std::char_traits<char>, DynamicBuffer, char, std::char_traits<char>,
std::is_move_constructible< detail::basic_streambuf_movable::value>{buffer};
detail::ostream_buffer<DynamicBuffer,
char, std::char_traits<char>>>::value>{buffer};
} }
} // beast } // beast