Refactor ostream:

* Fix overflow
* Better calculation for prepare, no read_size
* Improve tests and code coverage
This commit is contained in:
Vinnie Falco
2018-12-16 11:30:34 -08:00
parent 594a92e515
commit 991bae8486
7 changed files with 88 additions and 87 deletions

View File

@@ -17,6 +17,7 @@ Version 200
* Tidy up flat_static_buffer tests * Tidy up flat_static_buffer tests
* Add more tests for dynamic buffers * Add more tests for dynamic buffers
* Tidy up multi_buffer * Tidy up multi_buffer
* Refactor ostream
API Changes: API Changes:

View File

@@ -12,8 +12,8 @@
#include <boost/beast/core/buffers_prefix.hpp> #include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/buffers_range.hpp> #include <boost/beast/core/buffers_range.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/core/detail/type_traits.hpp> #include <boost/beast/core/detail/type_traits.hpp>
#include <boost/throw_exception.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <memory> #include <memory>
#include <iosfwd> #include <iosfwd>
@@ -50,7 +50,8 @@ operator<<(std::ostream& os,
buffers_helper<Buffers> const& v) buffers_helper<Buffers> const& v)
{ {
for(auto b : buffers_range(std::ref(v.b_))) for(auto b : buffers_range(std::ref(v.b_)))
os.write(static_cast<char const*>(b.data()), b.size()); os.write(static_cast<char const*>(
b.data()), b.size());
return os; return os;
} }
@@ -98,55 +99,40 @@ public:
ostream_buffer(DynamicBuffer& b) ostream_buffer(DynamicBuffer& b)
: b_(b) : b_(b)
{ {
prepare();
} }
int_type int_type
overflow(int_type ch) override overflow(int_type ch) override
{ {
if(! Traits::eq_int_type(ch, Traits::eof())) BOOST_ASSERT(! Traits::eq_int_type(
{ ch, Traits::eof()));
Traits::assign(*this->pptr(), sync();
static_cast<CharT>(ch));
flush(1);
prepare();
return ch;
}
flush();
return traits_type::eof();
}
int
sync() override
{
flush();
prepare();
return 0;
}
private:
void
prepare()
{
static std::size_t constexpr max_size = 65536; static std::size_t constexpr max_size = 65536;
auto const max_prepare = std::min<std::size_t>( auto const max_prepare = std::min<std::size_t>(
std::max<std::size_t>( std::max<std::size_t>(
512, b_.capacity() - b_.size()), 512, b_.capacity() - b_.size()),
std::min<std::size_t>( std::min<std::size_t>(
max_size, b_.max_size() - b_.size())); max_size, b_.max_size() - b_.size()));
if(max_prepare == 0)
return Traits::eof();
auto const bs = b_.prepare(max_prepare); auto const bs = b_.prepare(max_prepare);
auto const b = buffers_front(bs); auto const b = buffers_front(bs);
auto const p = static_cast<CharT*>(b.data()); auto const p = static_cast<CharT*>(b.data());
this->setp(p, this->setp(p, p + b.size() / sizeof(CharT));
p + b.size() / sizeof(CharT) - 1);
BOOST_ASSERT(b_.capacity() > b_.size());
return this->sputc(
Traits::to_char_type(ch));
} }
void int
flush(int extra = 0) sync() override
{ {
b_.commit( b_.commit(
(this->pptr() - this->pbase() + extra) * (this->pptr() - this->pbase()) *
sizeof(CharT)); sizeof(CharT));
return 0;
} }
}; };
@@ -180,55 +166,40 @@ public:
ostream_buffer(DynamicBuffer& b) ostream_buffer(DynamicBuffer& b)
: b_(b) : b_(b)
{ {
prepare();
} }
int_type int_type
overflow(int_type ch) override overflow(int_type ch) override
{ {
if(! Traits::eq_int_type(ch, Traits::eof())) BOOST_ASSERT(! Traits::eq_int_type(
{ ch, Traits::eof()));
Traits::assign(*this->pptr(), sync();
static_cast<CharT>(ch));
flush(1);
prepare();
return ch;
}
flush();
return traits_type::eof();
}
int
sync() override
{
flush();
prepare();
return 0;
}
private:
void
prepare()
{
static std::size_t constexpr max_size = 65536; static std::size_t constexpr max_size = 65536;
auto const max_prepare = std::min<std::size_t>( auto const max_prepare = std::min<std::size_t>(
std::max<std::size_t>( std::max<std::size_t>(
512, b_.capacity() - b_.size()), 512, b_.capacity() - b_.size()),
std::min<std::size_t>( std::min<std::size_t>(
max_size, b_.max_size() - b_.size())); max_size, b_.max_size() - b_.size()));
if(max_prepare == 0)
return Traits::eof();
auto const bs = b_.prepare(max_prepare); auto const bs = b_.prepare(max_prepare);
auto const b = buffers_front(bs); auto const b = buffers_front(bs);
auto const p = static_cast<CharT*>(b.data()); auto const p = static_cast<CharT*>(b.data());
this->setp(p, this->setp(p, p + b.size() / sizeof(CharT));
p + b.size() / sizeof(CharT) - 1);
BOOST_ASSERT(b_.capacity() > b_.size());
return this->sputc(
Traits::to_char_type(ch));
} }
void int
flush(int extra = 0) sync() override
{ {
b_.commit( b_.commit(
(this->pptr() - this->pbase() + extra) * (this->pptr() - this->pbase()) *
sizeof(CharT)); sizeof(CharT));
return 0;
} }
}; };
@@ -256,16 +227,14 @@ public:
template<class DynamicBuffer, class CharT, class Traits> template<class DynamicBuffer, class CharT, class Traits>
ostream_helper<DynamicBuffer, CharT, Traits, true>:: ostream_helper<DynamicBuffer, CharT, Traits, true>::
ostream_helper(DynamicBuffer& b) ostream_helper(DynamicBuffer& b)
: std::basic_ostream<CharT, Traits>( : std::basic_ostream<CharT, Traits>(&this->osb_)
&this->osb_)
, osb_(b) , osb_(b)
{ {
} }
template<class DynamicBuffer, class CharT, class Traits> template<class DynamicBuffer, class CharT, class Traits>
ostream_helper<DynamicBuffer, CharT, Traits, true>:: ostream_helper<DynamicBuffer, CharT, Traits, true>::
ostream_helper( ostream_helper(ostream_helper&& other)
ostream_helper&& other)
: std::basic_ostream<CharT, Traits>(&osb_) : std::basic_ostream<CharT, Traits>(&osb_)
, osb_(std::move(other.osb_)) , osb_(std::move(other.osb_))
{ {
@@ -304,7 +273,8 @@ public:
DynamicBuffer, CharT, Traits, false>>( DynamicBuffer, CharT, Traits, false>>(
new ostream_buffer<DynamicBuffer, new ostream_buffer<DynamicBuffer,
CharT, Traits, false>(b)) CharT, Traits, false>(b))
, std::basic_ostream<CharT, Traits>(this->member.get()) , std::basic_ostream<CharT, Traits>(
this->member.get())
{ {
} }
@@ -312,7 +282,8 @@ public:
: ostream_helper_base<ostream_buffer< : ostream_helper_base<ostream_buffer<
DynamicBuffer, CharT, Traits, false>>( DynamicBuffer, CharT, Traits, false>>(
std::move(other)) std::move(other))
, std::basic_ostream<CharT, Traits>(this->member.get()) , std::basic_ostream<CharT, Traits>(
this->member.get())
{ {
} }
}; };

View File

@@ -14,6 +14,7 @@
#include <boost/beast/core/multi_buffer.hpp> #include <boost/beast/core/multi_buffer.hpp>
#include <boost/beast/core/ostream.hpp> #include <boost/beast/core/ostream.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp> #include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/asio/streambuf.hpp> #include <boost/asio/streambuf.hpp>

View File

@@ -13,6 +13,7 @@
#include "buffer_test.hpp" #include "buffer_test.hpp"
#include <boost/beast/core/ostream.hpp> #include <boost/beast/core/ostream.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/core/string.hpp> #include <boost/beast/core/string.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp> #include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/asio/buffers_iterator.hpp> #include <boost/asio/buffers_iterator.hpp>

View File

@@ -13,6 +13,7 @@
#include "buffer_test.hpp" #include "buffer_test.hpp"
#include <boost/beast/core/ostream.hpp> #include <boost/beast/core/ostream.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/core/string.hpp> #include <boost/beast/core/string.hpp>
#include <boost/beast/core/type_traits.hpp> #include <boost/beast/core/type_traits.hpp>
#include <boost/beast/test/test_allocator.hpp> #include <boost/beast/test/test_allocator.hpp>

View File

@@ -11,6 +11,8 @@
#include <boost/beast/core/ostream.hpp> #include <boost/beast/core/ostream.hpp>
#include <boost/beast/core/buffers_to_string.hpp> #include <boost/beast/core/buffers_to_string.hpp>
#include <boost/beast/core/flat_buffer.hpp>
#include <boost/beast/core/flat_static_buffer.hpp>
#include <boost/beast/core/multi_buffer.hpp> #include <boost/beast/core/multi_buffer.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp> #include <boost/beast/_experimental/unit_test/suite.hpp>
#include <ostream> #include <ostream>
@@ -22,30 +24,53 @@ class ostream_test : public beast::unit_test::suite
{ {
public: public:
void void
run() override testOstream()
{ {
string_view const s = "0123456789abcdef";
BEAST_EXPECT(s.size() == 16);
// overflow
{ {
multi_buffer b; flat_static_buffer<16> b;
auto os = ostream(b);
os << "Hello, world!\n";
os.flush();
BEAST_EXPECT(buffers_to_string(b.data()) == "Hello, world!\n");
auto os2 = std::move(os);
}
{
auto const s =
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef"
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef"
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef"
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef"
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef"
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef"
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef"
"0123456789abcdef" "0123456789abcdef" "0123456789abcdef" "0123456789abcdef";
multi_buffer b;
ostream(b) << s; ostream(b) << s;
BEAST_EXPECT(buffers_to_string(b.data()) == s); BEAST_EXPECT(buffers_to_string(b.data()) == s);
} }
// max_size
{
flat_static_buffer<16> b;
auto os = ostream(b);
os << s;
os << '*';
BEAST_EXPECT(os.bad());
}
// max_size (exception
{
flat_static_buffer<16> b;
auto os = ostream(b);
os.exceptions(os.badbit);
os << s;
try
{
os << '*';
fail("missing exception", __FILE__, __LINE__);
}
catch(std::ios_base::failure const&)
{
pass();
}
catch(...)
{
fail("wrong exception", __FILE__, __LINE__);
}
}
}
void
run() override
{
testOstream();
} }
}; };

View File

@@ -13,6 +13,7 @@
#include "buffer_test.hpp" #include "buffer_test.hpp"
#include <boost/beast/core/ostream.hpp> #include <boost/beast/core/ostream.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/core/string.hpp> #include <boost/beast/core/string.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp> #include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/asio/buffers_iterator.hpp> #include <boost/asio/buffers_iterator.hpp>