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,45 +91,20 @@ 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;
explicit
ostream_buffer(DynamicBuffer& buf);
int_type
overflow(int_type ch) override;
int
sync() override;
private:
void
prepare();
void
flush(int extra = 0);
};
template<class DynamicBuffer, class CharT, class Traits>
ostream_buffer<DynamicBuffer, CharT, Traits>::
~ostream_buffer() noexcept ~ostream_buffer() noexcept
{ {
sync(); sync();
} }
template<class DynamicBuffer, class CharT, class Traits> explicit
ostream_buffer<DynamicBuffer, CharT, Traits>::
ostream_buffer(DynamicBuffer& buf) ostream_buffer(DynamicBuffer& buf)
: buf_(buf) : buf_(buf)
{ {
prepare(); prepare();
} }
template<class DynamicBuffer, class CharT, class Traits>
auto
ostream_buffer<DynamicBuffer, CharT, Traits>::
overflow(int_type ch) ->
int_type int_type
overflow(int_type ch) override
{ {
if(! Traits::eq_int_type(ch, Traits::eof())) if(! Traits::eq_int_type(ch, Traits::eof()))
{ {
@@ -123,19 +117,16 @@ overflow(int_type ch) ->
return traits_type::eof(); return traits_type::eof();
} }
template<class DynamicBuffer, class CharT, class Traits>
int int
ostream_buffer<DynamicBuffer, CharT, Traits>:: sync() override
sync()
{ {
flush(); flush();
prepare(); prepare();
return 0; return 0;
} }
template<class DynamicBuffer, class CharT, class Traits> private:
void void
ostream_buffer<DynamicBuffer, CharT, Traits>::
prepare() prepare()
{ {
using boost::asio::buffer_cast; using boost::asio::buffer_cast;
@@ -148,15 +139,94 @@ prepare()
p + buffer_size(mb) / sizeof(CharT) - 1); p + buffer_size(mb) / sizeof(CharT) - 1);
} }
template<class DynamicBuffer, class CharT, class Traits>
void void
ostream_buffer<DynamicBuffer, CharT, Traits>:: flush(int extra = 0)
flush(int extra)
{ {
buf_.commit( buf_.commit(
(this->pptr() - this->pbase() + extra) * (this->pptr() - this->pbase() + extra) *
sizeof(CharT)); 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 DynamicBuffer, class CharT, class Traits>
class ostream_buffer
<DynamicBuffer, CharT, Traits, false>
: public std::basic_streambuf<CharT, Traits>
{
using int_type = typename
std::basic_streambuf<CharT, Traits>::int_type;
using traits_type = typename
std::basic_streambuf<CharT, Traits>::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(
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<
DynamicBuffer, CharT, Traits, false>
: private ostream_helper_base<ostream_buffer<
DynamicBuffer, CharT, Traits, false>>
, public std::basic_ostream<CharT, Traits>
{
public:
explicit
ostream_helper(DynamicBuffer& buf) ostream_helper(DynamicBuffer& buf)
: boost::base_from_member<std::unique_ptr< : ostream_helper_base<ostream_buffer<
ostream_buffer<DynamicBuffer, CharT, Traits>>>( DynamicBuffer, CharT, Traits, false>>(
new ostream_buffer<DynamicBuffer, CharT, Traits>(buf)) new ostream_buffer<DynamicBuffer,
, std::basic_ostream<CharT, Traits>( CharT, Traits, false>(buf))
this->member.get()) , std::basic_ostream<CharT, Traits>(this->member.get())
{ {
} }
template<class DynamicBuffer, class CharT, class Traits>
ostream_helper<DynamicBuffer, CharT, Traits, false>::
ostream_helper(ostream_helper&& other) ostream_helper(ostream_helper&& other)
: boost::base_from_member<std::unique_ptr< : ostream_helper_base<ostream_buffer<
ostream_buffer<DynamicBuffer, CharT, Traits>>>( DynamicBuffer, CharT, Traits, false>>(
std::move(other.member)) std::move(other))
, std::basic_ostream<CharT, Traits>( , std::basic_ostream<CharT, Traits>(this->member.get())
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