diff --git a/CHANGELOG.md b/CHANGELOG.md index 96bf8e0c..8c4ce4d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ API Changes: * Refactor http::header contents * New ostream() returns dynamic buffer output stream +* New buffers() replaces to_string() -------------------------------------------------------------------------------- diff --git a/doc/quickref.xml b/doc/quickref.xml index b72d05ba..3c8c7f8a 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -176,11 +176,11 @@ bind_handler buffer_cat + buffers ostream prepare_buffer prepare_buffers system_category - to_string diff --git a/examples/ssl/websocket_ssl_example.cpp b/examples/ssl/websocket_ssl_example.cpp index bba99c7a..214d1833 100644 --- a/examples/ssl/websocket_ssl_example.cpp +++ b/examples/ssl/websocket_ssl_example.cpp @@ -5,7 +5,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include +#include #include #include #include @@ -45,5 +45,5 @@ int main() beast::websocket::opcode op; ws.read(op, sb); ws.close(beast::websocket::close_code::normal); - std::cout << to_string(sb.data()) << "\n"; + std::cout << beast::buffers(sb.data()) << "\n"; } diff --git a/examples/websocket_example.cpp b/examples/websocket_example.cpp index bda489be..3d7547f6 100644 --- a/examples/websocket_example.cpp +++ b/examples/websocket_example.cpp @@ -5,7 +5,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include +#include #include #include #include @@ -31,5 +31,5 @@ int main() beast::websocket::opcode op; ws.read(op, sb); ws.close(beast::websocket::close_code::normal); - std::cout << beast::to_string(sb.data()) << "\n"; + std::cout << beast::buffers(sb.data()) << "\n"; } diff --git a/include/beast/core.hpp b/include/beast/core.hpp index c60f8e88..75c27f07 100644 --- a/include/beast/core.hpp +++ b/include/beast/core.hpp @@ -17,19 +17,18 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include #include #include #include -#include #endif diff --git a/include/beast/core/detail/ostream.hpp b/include/beast/core/detail/ostream.hpp index 4eb5cbdc..01853070 100644 --- a/include/beast/core/detail/ostream.hpp +++ b/include/beast/core/detail/ostream.hpp @@ -19,6 +19,40 @@ namespace beast { namespace detail { +template +class buffers_helper +{ + Buffers b_; + +public: + explicit + buffers_helper(Buffers const& b) + : b_(b) + { + } + + template + friend + std::ostream& + operator<<(std::ostream& os, + buffers_helper const& v); +}; + +template +std::ostream& +operator<<(std::ostream& os, + buffers_helper const& v) +{ + using boost::asio::buffer_cast; + using boost::asio::buffer_size; + for(auto const& b : v.b_) + os.write(buffer_cast(b), + buffer_size(b)); + return os; +} + +//------------------------------------------------------------------------------ + template< class DynamicBuffer, class CharT, diff --git a/include/beast/core/ostream.hpp b/include/beast/core/ostream.hpp index a3186963..e991f5e7 100644 --- a/include/beast/core/ostream.hpp +++ b/include/beast/core/ostream.hpp @@ -17,6 +17,40 @@ namespace beast { +/** Return an object representing a @b ConstBufferSequence. + + This function wraps a reference to a buffer sequence and permits + the following operation: + + @li `operator<<` to `std::ostream`. No character translation is + performed; unprintable and null characters will be transferred + as-is to the output stream. + + @par Example + @code + streambuf sb; + ... + std::cout << buffers(sb.data()) << std::endl; + @endcode + + @param b An object meeting the requirements of @b ConstBufferSequence + to be streamed. The implementation will make a copy of this object. +*/ +template +#if BEAST_DOXYGEN +implementation_defined +#else +detail::buffers_helper +#endif +buffers(ConstBufferSequence const& b) +{ + static_assert(is_ConstBufferSequence< + ConstBufferSequence>::value, + "ConstBufferSequence not met"); + return detail::buffers_helper< + ConstBufferSequence>{b}; +} + /** Return an output stream that formats values into a @b DynamicBuffer. This function wraps the caller provided @b DynamicBuffer into diff --git a/include/beast/core/to_string.hpp b/include/beast/core/to_string.hpp deleted file mode 100644 index 14d32589..00000000 --- a/include/beast/core/to_string.hpp +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) 2013-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) -// - -#ifndef BEAST_TO_STRING_HPP -#define BEAST_TO_STRING_HPP - -#include -#include -#include -#include - -namespace beast { - -/** Convert a @b `ConstBufferSequence` to a `std::string`. - - This function will convert the octets in a buffer sequence to a string. - All octets will be inserted into the resulting string, including null - or unprintable characters. - - @param buffers The buffer sequence to convert. - - @return A string representing the contents of the input area. - - @note This function participates in overload resolution only if - the buffers parameter meets the requirements of @b `ConstBufferSequence`. -*/ -template -#if BEAST_DOXYGEN -std::string -#else -typename std::enable_if< - is_ConstBufferSequence::value, - std::string>::type -#endif -to_string(ConstBufferSequence const& buffers) -{ - using boost::asio::buffer_cast; - using boost::asio::buffer_size; - std::string s; - s.reserve(buffer_size(buffers)); - for(auto const& buffer : buffers) - s.append(buffer_cast(buffer), - buffer_size(buffer)); - return s; -} - -} // beast - -#endif diff --git a/scripts/blacklist.supp b/scripts/blacklist.supp deleted file mode 100644 index 08968f04..00000000 --- a/scripts/blacklist.supp +++ /dev/null @@ -1,39 +0,0 @@ -# Remember that this blacklist file is GLOBAL to all sanitizers -# Be therefore extremely careful when considering to add a sanitizer -# filter here instead of using a runtime suppression -# -# Remember also that filters here quite literally completely -# remove instrumentation altogether, so filtering here means -# that sanitizers such as tsan will false positive on problems -# introduced by code filtered here. -# -# The main use for this file is ubsan, as it's the only sanitizer -# without a runtime suppression facility. -# -# Be ESPECIALLY careful when filtering out entire source files! -# Try if at all possible to filter only functions using fun:regex -# Remember you must use mangled symbol names with fun:regex - - -#### Compile time filters for ubsan #### - -## The well known ubsan failure in libstdc++ extant for years :) -# Line 96:24: runtime error: load of value 4294967221, which is not a valid value for type 'std::_Ios_Fmtflags' -fun:*_Ios_Fmtflags* - -# boost/any.hpp:259:16: runtime error: downcast of address 0x000004392e70 which does not point to an object of type 'any::holder' -fun:*any_cast* - -# boost/lexical_cast.hpp:1625:43: runtime error: downcast of address 0x7fbb4fffbce8 which does not point to an object of type 'buffer_t' (aka 'parser_buf >, char>') -fun:*shl_input_streamable* - - - - -#### Compile time filters for asan #### - - -#### Compile time filters for msan #### - - -#### Compile time filters for tsan #### diff --git a/test/Jamfile b/test/Jamfile index 38759e84..bf5a2b0b 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -37,7 +37,6 @@ unit-test core-tests : core/static_string.cpp core/stream_concepts.cpp core/streambuf.cpp - core/to_string.cpp core/base64.cpp core/empty_base_optimization.cpp core/get_lowest_layer.cpp diff --git a/test/core/CMakeLists.txt b/test/core/CMakeLists.txt index 0c353d99..f1f654a6 100644 --- a/test/core/CMakeLists.txt +++ b/test/core/CMakeLists.txt @@ -30,7 +30,6 @@ add_executable (core-tests static_string.cpp stream_concepts.cpp streambuf.cpp - to_string.cpp base64.cpp empty_base_optimization.cpp get_lowest_layer.cpp diff --git a/test/core/buffers_adapter.cpp b/test/core/buffers_adapter.cpp index 9f8054c6..b14dc676 100644 --- a/test/core/buffers_adapter.cpp +++ b/test/core/buffers_adapter.cpp @@ -8,10 +8,12 @@ // Test that header file is self-contained. #include +#include #include #include #include #include +#include #include namespace beast { @@ -24,14 +26,8 @@ public: std::string to_string(ConstBufferSequence const& bs) { - using boost::asio::buffer_cast; - using boost::asio::buffer_size; - std::string s; - s.reserve(buffer_size(bs)); - for(auto const& b : bs) - s.append(buffer_cast(b), - buffer_size(b)); - return s; + return boost::lexical_cast< + std::string>(buffers(bs)); } void testBuffersAdapter() diff --git a/test/core/consuming_buffers.cpp b/test/core/consuming_buffers.cpp index d4a1dc47..2a10ab00 100644 --- a/test/core/consuming_buffers.cpp +++ b/test/core/consuming_buffers.cpp @@ -9,7 +9,7 @@ #include #include "buffer_test.hpp" -#include +#include #include #include #include @@ -19,6 +19,15 @@ namespace beast { class consuming_buffers_test : public beast::unit_test::suite { public: + template + static + std::string + to_string(ConstBufferSequence const& bs) + { + return boost::lexical_cast< + std::string>(buffers(bs)); + } + template static consuming_buffers diff --git a/test/core/flat_streambuf.cpp b/test/core/flat_streambuf.cpp index 77d79000..fec9c452 100644 --- a/test/core/flat_streambuf.cpp +++ b/test/core/flat_streambuf.cpp @@ -9,9 +9,10 @@ #include #include "buffer_test.hpp" -#include +#include #include #include +#include #include namespace beast { @@ -22,6 +23,15 @@ static_assert(is_DynamicBuffer::value, class flat_streambuf_test : public beast::unit_test::suite { public: + template + static + std::string + to_string(ConstBufferSequence const& bs) + { + return boost::lexical_cast< + std::string>(buffers(bs)); + } + template static bool diff --git a/test/core/ostream.cpp b/test/core/ostream.cpp index 055fbd15..f96fd8b7 100644 --- a/test/core/ostream.cpp +++ b/test/core/ostream.cpp @@ -10,10 +10,9 @@ #include #include +#include #include -#include - namespace beast { class ostream_test : public beast::unit_test::suite @@ -23,7 +22,8 @@ public: { streambuf sb; ostream(sb) << "Hello, world!\n"; - BEAST_EXPECT(to_string(sb.data()) == "Hello, world!\n"); + BEAST_EXPECT(boost::lexical_cast( + buffers(sb.data())) == "Hello, world!\n"); } }; diff --git a/test/core/streambuf.cpp b/test/core/streambuf.cpp index 02a7b56e..892aabd6 100644 --- a/test/core/streambuf.cpp +++ b/test/core/streambuf.cpp @@ -10,7 +10,7 @@ #include "buffer_test.hpp" #include -#include +#include #include #include #include @@ -26,6 +26,15 @@ static_assert(is_DynamicBuffer::value, ""); class basic_streambuf_test : public beast::unit_test::suite { public: + template + static + std::string + to_string(ConstBufferSequence const& bs) + { + return boost::lexical_cast< + std::string>(buffers(bs)); + } + template static bool diff --git a/test/core/to_string.cpp b/test/core/to_string.cpp deleted file mode 100644 index e449dd33..00000000 --- a/test/core/to_string.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (c) 2013-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) -// - -// Test that header file is self-contained. -#include - -#include -#include - -namespace beast { - -class to_string_test : public beast::unit_test::suite -{ -public: - void run() - { - BEAST_EXPECT(to_string(boost::asio::const_buffers_1("x", 1)) == "x"); - } -}; - -BEAST_DEFINE_TESTSUITE(to_string,core,beast); - -} // beast - diff --git a/test/http/chunk_encode.cpp b/test/http/chunk_encode.cpp index 9bbe68f3..881fa4ca 100644 --- a/test/http/chunk_encode.cpp +++ b/test/http/chunk_encode.cpp @@ -8,8 +8,9 @@ // Test that header file is self-contained. #include -#include +#include #include +#include namespace beast { namespace http { @@ -30,6 +31,15 @@ public: } }; + template + static + std::string + to_string(ConstBufferSequence const& bs) + { + return boost::lexical_cast< + std::string>(buffers(bs)); + } + static void encode1(std::string& s, final_chunk const& fc) diff --git a/test/http/dynamic_body.cpp b/test/http/dynamic_body.cpp index 77b86a91..5b06e030 100644 --- a/test/http/dynamic_body.cpp +++ b/test/http/dynamic_body.cpp @@ -8,7 +8,7 @@ // Test that header file is self-contained. #include -#include +#include #include #include #include @@ -25,7 +25,8 @@ class dynamic_body_test : public beast::unit_test::suite boost::asio::io_service ios_; public: - void run() override + void + run() override { std::string const s = "HTTP/1.1 200 OK\r\n" @@ -38,7 +39,8 @@ public: streambuf sb; read(ss, sb, p); auto const& m = p.get(); - BEAST_EXPECT(to_string(m.body.data()) == "xyz"); + BEAST_EXPECT(boost::lexical_cast( + buffers(m.body.data())) == "xyz"); BEAST_EXPECT(boost::lexical_cast(m) == s); } }; diff --git a/test/http/parser_bench.cpp b/test/http/parser_bench.cpp index bf555f9b..9344411b 100644 --- a/test/http/parser_bench.cpp +++ b/test/http/parser_bench.cpp @@ -10,9 +10,10 @@ #include #include +#include #include -#include #include +#include #include #include #include @@ -31,6 +32,15 @@ public: corpus cres_; std::size_t size_ = 0; + template + static + std::string + to_string(ConstBufferSequence const& bs) + { + return boost::lexical_cast< + std::string>(buffers(bs)); + } + parser_bench_test() { creq_ = build_corpus(N/2, std::true_type{}); diff --git a/test/http/write.cpp b/test/http/write.cpp index 51bfc2f0..656e59e6 100644 --- a/test/http/write.cpp +++ b/test/http/write.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/test/websocket/ssl/ssl_server.cpp b/test/websocket/ssl/ssl_server.cpp index 0303e4a4..cb6896c1 100644 --- a/test/websocket/ssl/ssl_server.cpp +++ b/test/websocket/ssl/ssl_server.cpp @@ -8,7 +8,7 @@ #include "websocket_async_ssl_echo_server.hpp" #include -#include +#include #include #include #include @@ -126,7 +126,7 @@ public: // Secure WebSocket connect and send message using Beast beast::websocket::stream ws{stream}; ws.handshake("localhost", "/"); - ws.write(boost::asio::buffer("Hello, world!")); + ws.write(boost::asio::buffer("Hello, world!", 13)); // Receive Secure WebSocket message, print and close using Beast beast::streambuf sb; @@ -146,9 +146,8 @@ public: if(se.code() != beast::websocket::error::closed) throw; } - log << to_string(sb.data()) << std::endl; - - pass(); + BEAST_EXPECT(boost::lexical_cast( + buffers(sb.data())) == "Hello, world!"); } }; diff --git a/test/websocket/stream.cpp b/test/websocket/stream.cpp index 2d3e42ee..0a1e4254 100644 --- a/test/websocket/stream.cpp +++ b/test/websocket/stream.cpp @@ -11,8 +11,8 @@ #include "websocket_async_echo_server.hpp" #include "websocket_sync_echo_server.hpp" +#include #include -#include #include #include #include @@ -38,6 +38,15 @@ public: using address_type = boost::asio::ip::address; using socket_type = boost::asio::ip::tcp::socket; + template + static + std::string + to_string(ConstBufferSequence const& bs) + { + return boost::lexical_cast< + std::string>(buffers(bs)); + } + struct con { stream ws; @@ -1169,7 +1178,8 @@ public: ); } - void testMask(endpoint_type const& ep, + void + testMask(endpoint_type const& ep, yield_context do_yield) { {