mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 13:27:33 +02:00
ostream workaround for gcc 4.8.4
This commit is contained in:
@@ -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
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user