Skip to content

Commit c97b368

Browse files
authored
Merge pull request #31 from basiliscos/experimental-boost-1.70
Experimental boost 1.70
2 parents 7db8dba + 82d38ae commit c97b368

File tree

12 files changed

+240
-51
lines changed

12 files changed

+240
-51
lines changed

.travis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ os:
88
- linux
99

1010
before_script:
11-
- wget -q -O - https://sourceforge.net/projects/boost/files/boost/1.69.0/boost_1_69_0.tar.gz | tar -xz
12-
- cd boost_1_69_0 && ./bootstrap.sh --with-libraries=coroutine,context,chrono,system,thread,regex,filesystem,program_options
11+
- wget -q -O - https://sourceforge.net/projects/boost/files/boost/1.70.0/boost_1_70_0.tar.gz | tar -xz
12+
- cd boost_1_70_0 && ./bootstrap.sh --with-libraries=coroutine,context,chrono,system,thread,regex,filesystem,program_options
1313
- ./b2 --ignore-site-config && cd ..
1414
- mkdir build
1515
- cd build
16-
- cmake -DBOOST_ROOT=`pwd`/../boost_1_69_0 ..
16+
- cmake -DBOOST_ROOT=`pwd`/../boost_1_70_0 ..
1717

1818
addons:
1919
apt:

CMakeLists.txt

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,14 @@ if(WIN32)
7272
set(LINK_DEPENDENCIES ${Boost_LIBRARIES} catch_lib)
7373
add_definitions(-DBOOST_ALL_DYN_LINK -DBOOST_THREAD_USE_LIB -D_WIN32_WINNT=0x0501)
7474
else()
75-
add_definitions(-Wall -Wextra -pedantic -Werror)
75+
#add_definitions(-Wall -Wextra -pedantic -Werror)
76+
add_definitions(-Wall -Wextra -pedantic)
7677
#add_definitions(-fsanitize=undefined -fsanitize=address -fno-omit-frame-pointer)
7778
set(LINK_DEPENDENCIES pthread ${Boost_LIBRARIES} catch_lib) # asan ubsan
7879
endif()
7980

81+
set(BOOST_VERSION_OK, (Boost_MAJOR_VERSION GREATER_EQUAL 1) AND (Boost_MINOR_VERSION GREATER_EQUAL 70))
82+
8083
add_subdirectory(examples)
8184

8285
add_executable(t-05-protocol t/05-protocol.cpp)
@@ -137,9 +140,11 @@ add_executable(t-19-transaction t/19-transaction.cpp)
137140
target_link_libraries(t-19-transaction ${LINK_DEPENDENCIES})
138141
add_test("t-19-transaction" t-19-transaction)
139142

140-
add_executable(t-20-promise t/20-promise.cpp)
141-
target_link_libraries(t-20-promise ${LINK_DEPENDENCIES})
142-
add_test("t-20-promise" t-20-promise)
143+
if(BOOST_VERSION_OK)
144+
add_executable(t-20-promise t/20-promise.cpp)
145+
target_link_libraries(t-20-promise ${LINK_DEPENDENCIES})
146+
add_test("t-20-promise" t-20-promise)
147+
endif()
143148

144149
add_executable(t-21-coroutine t/21-coroutine.cpp)
145150
target_link_libraries(t-21-coroutine ${LINK_DEPENDENCIES})
@@ -153,3 +158,8 @@ add_executable(t-23-stream t/23-stream.cpp)
153158
target_link_libraries(t-23-stream ${LINK_DEPENDENCIES})
154159
add_test("t-23-stream" t-23-stream)
155160

161+
if(BOOST_VERSION_OK)
162+
add_executable(t-24-dynbuff t/24-dynbuff.cpp)
163+
target_link_libraries(t-24-dynbuff ${LINK_DEPENDENCIES})
164+
add_test("t-24-dynbuff" t-24-dynbuff)
165+
endif()

examples/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ target_link_libraries(stream-parse ${LINK_DEPENDENCIES})
88
add_executable(synch-subscription synch-subscription.cpp)
99
target_link_libraries(synch-subscription ${LINK_DEPENDENCIES})
1010

11-
add_executable(speed_test_async_multi speed_test_async_multi.cpp)
12-
target_link_libraries(speed_test_async_multi ${LINK_DEPENDENCIES})
11+
if(BOOST_VERSION_OK)
12+
add_executable(speed_test_async_multi speed_test_async_multi.cpp)
13+
target_link_libraries(speed_test_async_multi ${LINK_DEPENDENCIES})
14+
endif()
1315

1416
add_executable(multi-threads-1 multi-threads-1.cpp)
1517
target_link_libraries(multi-threads-1 ${LINK_DEPENDENCIES})

examples/speed_test_async_multi.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,15 @@ int main(int argc, char **argv) {
5353
// common setup
5454
using socket_t = asio::ip::tcp::socket;
5555
using next_layer_t = socket_t;
56-
using Buffer = boost::asio::streambuf;
56+
//using Buffer = boost::asio::streambuf;
57+
using Buffer = boost::asio::dynamic_string_buffer<
58+
std::string::value_type,
59+
std::string::traits_type,
60+
std::string::allocator_type
61+
>;
5762
using Iterator = typename r::to_iterator<Buffer>::iterator_t;
58-
//using policy_t = r::parsing_policy::drop_result;
59-
using policy_t = r::parsing_policy::keep_result;
63+
using policy_t = r::parsing_policy::drop_result;
64+
//using policy_t = r::parsing_policy::keep_result;
6065

6166
if (argc < 2) {
6267
std::cout << "Usage : " << argv[0] << " ip:port \n";
@@ -96,7 +101,11 @@ int main(int argc, char **argv) {
96101
// wrap it into bredis connection
97102
r::Connection<next_layer_t> c(std::move(socket));
98103

99-
Buffer tx_buff, rx_buff;
104+
std::string tx_backend, rx_backend;
105+
//tx_backend.reserve(cmds_count * 4);
106+
//rx_backend.reserve(cmds_count * 4);
107+
Buffer tx_buff(tx_backend), rx_buff(rx_backend);
108+
//Buffer tx_buff, rx_buff;
100109
std::promise<void> completion_promise;
101110
auto completion_future = completion_promise.get_future();
102111

@@ -109,7 +118,7 @@ int main(int argc, char **argv) {
109118
// cannot be done with drop_result
110119
//auto &replies = get<r::markers::array_holder_t<Iterator>>(r.result);
111120
//count += replies.elements.size() - 1;
112-
count = cmds_count;
121+
count = static_cast<int>(cmds_count);
113122
completion_promise.set_value();
114123
std::cout << "done reading...\n";
115124
},

include/bredis/Connection.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
#include <boost/asio.hpp>
2121
#include <boost/asio/async_result.hpp>
22-
#include <boost/asio/handler_type.hpp>
2322
#include <boost/utility/string_ref.hpp>
2423

2524
#include "Command.hpp"

include/bredis/Protocol.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ class Protocol {
2121
static inline parse_result_t<Iterator, Policy> parse(const Iterator &from,
2222
const Iterator &to);
2323

24-
static inline std::ostream &serialize(std::ostream &buff,
25-
const single_command_t &cmd);
24+
template <typename DynamicBuffer>
25+
static inline void serialize(DynamicBuffer &buff,
26+
const single_command_t &cmd);
2627
};
2728

2829
} // namespace bredis

include/bredis/impl/common.ipp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,20 @@ template <typename Iterator> class MatchResult {
7474
}
7575
};
7676

77+
template <typename DynamicBuffer>
7778
class command_serializer_visitor : public boost::static_visitor<void> {
7879
private:
79-
std::ostream &out_;
80+
DynamicBuffer &buff_;
8081

8182
public:
82-
command_serializer_visitor(std::ostream &out) : out_{out} {}
83+
command_serializer_visitor(DynamicBuffer &buff) : buff_{buff} {}
8384
void operator()(const single_command_t &value) const {
84-
out_.imbue(std::locale::classic());
85-
Protocol::serialize(out_, value);
85+
Protocol::serialize(buff_, value);
8686
}
8787

8888
void operator()(const command_container_t &value) const {
89-
out_.imbue(std::locale::classic());
9089
for (const auto &cmd : value) {
91-
Protocol::serialize(out_, cmd);
90+
Protocol::serialize(buff_, cmd);
9291
}
9392
}
9493
};

include/bredis/impl/connection.ipp

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,20 @@ Connection<NextLayer>::async_write(DynamicBuffer &tx_buff,
2626
WriteCallback &&write_callback) {
2727
namespace asio = boost::asio;
2828
namespace sys = boost::system;
29+
2930
using boost::asio::async_write;
3031
using Signature = void(boost::system::error_code, std::size_t);
31-
using real_handler_t =
32-
typename asio::handler_type<WriteCallback, Signature>::type;
32+
using Callback = std::decay_t<WriteCallback>;
33+
using AsyncResult = asio::async_result<Callback, Signature>;
34+
using CompletionHandler = typename AsyncResult::completion_handler_type;
35+
using serializer_t = command_serializer_visitor<DynamicBuffer>;
3336

34-
std::ostream os(&tx_buff);
35-
boost::apply_visitor(command_serializer_visitor(os), command);
37+
boost::apply_visitor(serializer_t(tx_buff), command);
3638

37-
real_handler_t handler(std::forward<WriteCallback>(write_callback));
38-
return async_write(stream_, tx_buff, handler);
39+
CompletionHandler handler(std::forward<WriteCallback>(write_callback));
40+
AsyncResult result(handler);
41+
async_write(stream_, tx_buff, std::move(handler));
42+
return result.get();
3943
}
4044

4145
template <typename NextLayer>
@@ -49,31 +53,35 @@ Connection<NextLayer>::async_read(DynamicBuffer &rx_buff,
4953

5054
namespace asio = boost::asio;
5155
namespace sys = boost::system;
56+
5257
using boost::asio::async_read_until;
5358
using Iterator = typename to_iterator<DynamicBuffer>::iterator_t;
5459
using ParseResult = BREDIS_PARSE_RESULT(DynamicBuffer, Policy);
5560
using Signature = void(boost::system::error_code, ParseResult);
56-
using real_handler_t =
57-
typename asio::handler_type<ReadCallback, Signature>::type;
61+
using Callback = std::decay_t<ReadCallback>;
62+
using AsyncResult = asio::async_result<Callback, Signature>;
63+
using CompletionHandler = typename AsyncResult::completion_handler_type;
64+
using ReadOp =
65+
async_read_op<NextLayer, DynamicBuffer, CompletionHandler, Policy>;
5866

59-
real_handler_t real_handler(std::forward<ReadCallback>(read_callback));
60-
asio::async_result<real_handler_t> async_result(real_handler);
67+
CompletionHandler handler(std::forward<ReadCallback>(read_callback));
68+
AsyncResult result(handler);
6169

62-
async_read_op<NextLayer, DynamicBuffer, real_handler_t, Policy> async_op(
63-
std::move(real_handler), stream_, rx_buff, replies_count);
70+
ReadOp async_op(std::move(handler), stream_, rx_buff, replies_count);
6471

6572
async_read_until(stream_, rx_buff, MatchResult<Iterator>(replies_count),
6673
std::move(async_op));
67-
return async_result.get();
74+
return result.get();
6875
}
6976

7077
template <typename NextLayer>
7178
void Connection<NextLayer>::write(const command_wrapper_t &command,
7279
boost::system::error_code &ec) {
7380
namespace asio = boost::asio;
7481
asio::streambuf tx_buff;
75-
std::ostream os(&tx_buff);
76-
boost::apply_visitor(command_serializer_visitor(os), command);
82+
using serializer_t = command_serializer_visitor<asio::streambuf>;
83+
84+
boost::apply_visitor(serializer_t(tx_buff), command);
7785
asio::write(stream_, tx_buff, ec);
7886
}
7987

@@ -93,6 +101,7 @@ Connection<NextLayer>::read(DynamicBuffer &rx_buff,
93101
boost::system::error_code &ec) {
94102
namespace asio = boost::asio;
95103
using boost::asio::read_until;
104+
96105
using Iterator = typename to_iterator<DynamicBuffer>::iterator_t;
97106
using Policy = bredis::parsing_policy::keep_result;
98107
using result_t = BREDIS_PARSE_RESULT(DynamicBuffer, Policy);

include/bredis/impl/protocol.ipp

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
#pragma once
88

99
#include <algorithm>
10+
#include <boost/asio/buffer.hpp>
1011
#include <boost/asio/buffers_iterator.hpp>
1112
#include <boost/lexical_cast.hpp>
1213
#include <boost/variant.hpp>
14+
#include <cstdio>
1315
#include <errno.h>
1416
#include <stdlib.h>
1517
#include <string>
@@ -434,14 +436,56 @@ parse_result_t<Iterator, Policy> Protocol::parse(const Iterator &from,
434436
return details::raw_parse<Iterator, Policy>(from, to);
435437
}
436438

437-
std::ostream &Protocol::serialize(std::ostream &buff,
438-
const single_command_t &cmd) {
439-
buff << '*' << (cmd.arguments.size()) << terminator;
439+
inline std::size_t size_for_int(std::size_t arg) {
440+
std::size_t r = 0;
441+
while (arg) {
442+
++r;
443+
arg /= 10;
444+
}
445+
return r;
446+
}
447+
448+
inline std::size_t command_size(const single_command_t &cmd) {
449+
std::size_t sz = 1 /* * */
450+
+ size_for_int(cmd.arguments.size()) /* args size */
451+
+ terminator.size;
452+
453+
for (const auto &arg : cmd.arguments) {
454+
sz += 1 /* $ */
455+
+ size_for_int(arg.size()) /* argument size */
456+
+ terminator.size + arg.size() + terminator.size;
457+
}
458+
return sz;
459+
}
460+
461+
template <typename DynamicBuffer>
462+
inline void Protocol::serialize(DynamicBuffer &buff,
463+
const single_command_t &cmd) {
464+
465+
auto it = buff.prepare(command_size(cmd));
466+
constexpr std::size_t buff_sz = 64;
467+
using namespace boost::asio;
468+
char data[buff_sz];
469+
std::size_t total =
470+
snprintf(data, buff_sz, "*%zu\r\n", cmd.arguments.size());
471+
buffer_copy(it, buffer(data, total));
472+
it += total;
440473

441474
for (const auto &arg : cmd.arguments) {
442-
buff << '$' << arg.size() << terminator << arg << terminator;
475+
auto bytes = snprintf(data, buff_sz, "$%zu\r\n", arg.size());
476+
buffer_copy(it, buffer(data, bytes));
477+
it += bytes;
478+
total += bytes;
479+
480+
buffer_copy(it, buffer(arg.data(), arg.size()));
481+
it += arg.size();
482+
total += arg.size();
483+
484+
buffer_copy(it, buffer("\r\n", terminator.size));
485+
total += terminator.size;
486+
it += terminator.size;
443487
}
444-
return buff;
488+
buff.commit(total);
445489
}
446490

447491
} // namespace bredis

t/05-protocol.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <boost/asio/buffer.hpp>
22
#include <vector>
33

4+
#include <boost/asio.hpp>
45
#include "bredis/MarkerHelpers.hpp"
56
#include "bredis/Protocol.hpp"
67
#include "catch.hpp"
@@ -442,10 +443,24 @@ TEST_CASE("overfilled buffer", "[protocol]") {
442443
nullptr);
443444
}
444445

445-
TEST_CASE("serialize", "[protocol]") {
446-
std::stringstream buff;
446+
TEST_CASE("serialize + streambuf", "[protocol]") {
447+
boost::asio::streambuf buff;
447448
r::single_command_t cmd("LLEN", "fmm.cheap-travles2");
448449
r::Protocol::serialize(buff, cmd);
449450
std::string expected("*2\r\n$4\r\nLLEN\r\n$18\r\nfmm.cheap-travles2\r\n");
450-
REQUIRE(buff.str() == expected);
451+
452+
char data[128] = {0};
453+
asio::buffer_copy(asio::buffer(data), asio::buffer(buff.data(), buff.size()));
454+
REQUIRE(data == expected);
455+
}
456+
457+
TEST_CASE("serialize + dynamic_string_buffer", "[protocol]") {
458+
r::single_command_t cmd("LLEN", "fmm.cheap-travles2");
459+
std::string buff_backend;
460+
using Buff = asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char>>;
461+
auto buff = Buff(buff_backend);
462+
r::Protocol::serialize(buff, cmd);
463+
std::string expected("*2\r\n$4\r\nLLEN\r\n$18\r\nfmm.cheap-travles2\r\n");
464+
std::string copy(std::begin(buff_backend), std::begin(buff_backend) + buff.size());
465+
REQUIRE(copy == expected);
451466
}

0 commit comments

Comments
 (0)