summaryrefslogtreecommitdiff
path: root/boost/beast/core/detail/ostream.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/core/detail/ostream.hpp')
-rw-r--r--boost/beast/core/detail/ostream.hpp319
1 files changed, 319 insertions, 0 deletions
diff --git a/boost/beast/core/detail/ostream.hpp b/boost/beast/core/detail/ostream.hpp
new file mode 100644
index 0000000000..8d6eb94f51
--- /dev/null
+++ b/boost/beast/core/detail/ostream.hpp
@@ -0,0 +1,319 @@
+//
+// Copyright (c) 2016-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)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_DETAIL_OSTREAM_HPP
+#define BOOST_BEAST_DETAIL_OSTREAM_HPP
+
+#include <boost/beast/core/buffers_prefix.hpp>
+#include <boost/beast/core/read_size.hpp>
+#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/asio/buffer.hpp>
+#include <memory>
+#include <iosfwd>
+#include <streambuf>
+#include <type_traits>
+#include <utility>
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+template<class Buffers>
+class buffers_helper
+{
+ Buffers b_;
+
+public:
+ explicit
+ buffers_helper(Buffers const& b)
+ : b_(b)
+ {
+ }
+
+ template<class B>
+ friend
+ std::ostream&
+ operator<<(std::ostream& os,
+ buffers_helper<B> const& v);
+};
+
+template<class Buffers>
+std::ostream&
+operator<<(std::ostream& os,
+ buffers_helper<Buffers> const& v)
+{
+ for(auto b : buffers_range(v.b_))
+ os.write(
+ reinterpret_cast<char const*>(b.data()),
+ b.size());
+ return os;
+}
+
+//------------------------------------------------------------------------------
+
+struct basic_streambuf_movable_helper :
+ std::basic_streambuf<char, std::char_traits<char>>
+{
+ basic_streambuf_movable_helper(
+ basic_streambuf_movable_helper&&) = default;
+};
+
+using basic_streambuf_movable =
+ std::is_move_constructible<basic_streambuf_movable_helper>;
+
+//------------------------------------------------------------------------------
+
+template<class DynamicBuffer,
+ class CharT, class Traits, bool isMovable>
+class ostream_buffer;
+
+template<class DynamicBuffer, class CharT, class Traits>
+class ostream_buffer
+ <DynamicBuffer, CharT, Traits, true>
+ : 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&&) = 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(),
+ static_cast<CharT>(ch));
+ flush(1);
+ prepare();
+ return ch;
+ }
+ flush();
+ return traits_type::eof();
+ }
+
+ int
+ sync() override
+ {
+ flush();
+ prepare();
+ return 0;
+ }
+
+private:
+ void
+ prepare()
+ {
+ auto bs = buf_.prepare(
+ read_size_or_throw(buf_, max_size));
+ auto const b = buffers_front(bs);
+ auto const p = reinterpret_cast<CharT*>(b.data());
+ this->setp(p,
+ p + b.size() / 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 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(),
+ static_cast<CharT>(ch));
+ flush(1);
+ prepare();
+ return ch;
+ }
+ flush();
+ return traits_type::eof();
+ }
+
+ int
+ sync() override
+ {
+ flush();
+ prepare();
+ return 0;
+ }
+
+private:
+ void
+ prepare()
+ {
+ auto bs = buf_.prepare(
+ read_size_or_throw(buf_, max_size));
+ auto const b = buffers_front(bs);
+ auto const p = reinterpret_cast<CharT*>(b.data());
+ this->setp(p,
+ p + b.size() / sizeof(CharT) - 1);
+ }
+
+ void
+ flush(int extra = 0)
+ {
+ buf_.commit(
+ (this->pptr() - this->pbase() + extra) *
+ sizeof(CharT));
+ }
+};
+
+//------------------------------------------------------------------------------
+
+template<class DynamicBuffer,
+ class CharT, class Traits, bool isMovable>
+class ostream_helper;
+
+template<class DynamicBuffer, class CharT, class Traits>
+class ostream_helper<
+ DynamicBuffer, CharT, Traits, true>
+ : public std::basic_ostream<CharT, Traits>
+{
+ ostream_buffer<
+ DynamicBuffer, CharT, Traits, true> osb_;
+
+public:
+ explicit
+ ostream_helper(DynamicBuffer& buf);
+
+ ostream_helper(ostream_helper&& other);
+};
+
+template<class DynamicBuffer, class CharT, class Traits>
+ostream_helper<DynamicBuffer, CharT, Traits, true>::
+ostream_helper(DynamicBuffer& buf)
+ : std::basic_ostream<CharT, Traits>(
+ &this->osb_)
+ , osb_(buf)
+{
+}
+
+template<class DynamicBuffer, class CharT, class Traits>
+ostream_helper<DynamicBuffer, CharT, Traits, true>::
+ostream_helper(
+ ostream_helper&& other)
+ : std::basic_ostream<CharT, Traits>(&osb_)
+ , osb_(std::move(other.osb_))
+{
+}
+
+// This work-around is for libstdc++ versions that
+// don't have a movable std::basic_streambuf
+
+template<class T>
+class ostream_helper_base
+{
+protected:
+ std::unique_ptr<T> member;
+
+ ostream_helper_base(
+ ostream_helper_base&&) = default;
+
+ explicit
+ ostream_helper_base(T* t)
+ : member(t)
+ {
+ }
+};
+
+template<class DynamicBuffer, class CharT, class Traits>
+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_base<ostream_buffer<
+ DynamicBuffer, CharT, Traits, false>>(
+ new ostream_buffer<DynamicBuffer,
+ CharT, Traits, false>(buf))
+ , std::basic_ostream<CharT, Traits>(this->member.get())
+ {
+ }
+
+ ostream_helper(ostream_helper&& other)
+ : ostream_helper_base<ostream_buffer<
+ DynamicBuffer, CharT, Traits, false>>(
+ std::move(other))
+ , std::basic_ostream<CharT, Traits>(this->member.get())
+ {
+ }
+};
+
+} // detail
+} // beast
+} // boost
+
+#endif