mirror of
https://github.com/boostorg/redis.git
synced 2026-02-09 23:32:35 +00:00
More changes in the architecture.
This commit is contained in:
@@ -28,22 +28,6 @@
|
||||
|
||||
namespace aedis { namespace resp {
|
||||
|
||||
inline
|
||||
void print_command_raw(std::string const& data, int n)
|
||||
{
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (data[i] == '\n') {
|
||||
std::cout << "\\n";
|
||||
continue;
|
||||
}
|
||||
if (data[i] == '\r') {
|
||||
std::cout << "\\r";
|
||||
continue;
|
||||
}
|
||||
std::cout << data[i];
|
||||
}
|
||||
}
|
||||
|
||||
// The parser supports up to 5 levels of nested structures. The first
|
||||
// element in the sizes stack is a sentinel and must be different from
|
||||
// 1.
|
||||
@@ -253,28 +237,20 @@ auto async_read_type(
|
||||
stream);
|
||||
}
|
||||
|
||||
struct receiver_ignore {
|
||||
template <class Event>
|
||||
void receive(response_id<Event> const&) {}
|
||||
template <class Event>
|
||||
void receive_transaction(std::queue<response_id<Event>>) {}
|
||||
};
|
||||
|
||||
template <
|
||||
class AsyncReadWriteStream,
|
||||
class Event,
|
||||
class ResponseBuffer,
|
||||
class Receiver = receiver_ignore>
|
||||
class Receiver>
|
||||
net::awaitable<void>
|
||||
async_reader(
|
||||
AsyncReadWriteStream& socket,
|
||||
std::queue<request<Event>>& reqs,
|
||||
ResponseBuffer& resps,
|
||||
Receiver recv = receiver_ignore{})
|
||||
Receiver& recv,
|
||||
std::queue<request<typename Receiver::event_type>>& reqs)
|
||||
{
|
||||
using response_id_type = response_id<Event>;
|
||||
using event_type = typename Receiver::event_type;
|
||||
using response_id_type = response_id<event_type>;
|
||||
|
||||
std::string buffer;
|
||||
resp::response_buffers resps;
|
||||
|
||||
// Used to queue the events of a transaction.
|
||||
std::queue<response_id_type> trans;
|
||||
@@ -327,7 +303,7 @@ async_reader(
|
||||
net::use_awaitable);
|
||||
|
||||
trans.pop(); // Removes multi.
|
||||
recv.receive_transaction(std::move(trans));
|
||||
resps.forward_transaction(std::move(trans), recv);
|
||||
trans = {};
|
||||
|
||||
req.events.pop(); // exec
|
||||
@@ -351,7 +327,7 @@ async_reader(
|
||||
*tmp,
|
||||
net::use_awaitable);
|
||||
|
||||
recv.receive(id);
|
||||
resps.forward(id, recv);
|
||||
|
||||
if (t != type::push)
|
||||
req.events.pop();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include "type.hpp"
|
||||
@@ -16,78 +17,97 @@
|
||||
|
||||
namespace aedis { namespace resp {
|
||||
|
||||
class receiver_print {
|
||||
template <class Event>
|
||||
class receiver_base {
|
||||
public:
|
||||
using event_type = Event;
|
||||
|
||||
virtual void on_array(command cmd, Event ev, response_array::data_type& v) noexcept
|
||||
{ print(v); }
|
||||
virtual void on_push(command cmd, Event ev, response_array::data_type& v) noexcept
|
||||
{ print(v); }
|
||||
virtual void on_map(command cmd, Event ev, response_array::data_type& v) noexcept
|
||||
{ print(v); }
|
||||
virtual void on_set(command cmd, Event ev, response_array::data_type& v) noexcept
|
||||
{ print(v); }
|
||||
virtual void on_attribute(command cmd, Event ev, response_array::data_type& v) noexcept
|
||||
{ print(v); }
|
||||
virtual void on_simple_string(command cmd, Event ev, response_simple_string::data_type& v) noexcept
|
||||
{ std::cout << v << std::endl; }
|
||||
virtual void on_simple_error(command cmd, Event ev, response_simple_error::data_type& v) noexcept
|
||||
{ std::cout << v << std::endl; }
|
||||
virtual void on_number(command cmd, Event ev, response_number::data_type& v) noexcept
|
||||
{ std::cout << v << std::endl; }
|
||||
virtual void on_double(command cmd, Event ev, response_double::data_type& v) noexcept
|
||||
{ std::cout << v << std::endl; }
|
||||
virtual void on_big_number(command cmd, Event ev, response_big_number::data_type& v) noexcept
|
||||
{ std::cout << v << std::endl; }
|
||||
virtual void on_boolean(command cmd, Event ev, response_bool::data_type& v) noexcept
|
||||
{ std::cout << v << std::endl; }
|
||||
virtual void on_blob_string(command cmd, Event ev, response_blob_string::data_type& v) noexcept
|
||||
{ std::cout << v << std::endl; }
|
||||
virtual void on_blob_error(command cmd, Event ev, response_blob_error::data_type& v) noexcept
|
||||
{ std::cout << v << std::endl; }
|
||||
virtual void on_verbatim_string(command cmd, Event ev, response_verbatim_string::data_type& v) noexcept
|
||||
{ std::cout << v << std::endl; }
|
||||
virtual void on_streamed_string_part(command cmd, Event ev, response_streamed_string_part::data_type& v) noexcept
|
||||
{ std::cout << v << std::endl; }
|
||||
};
|
||||
|
||||
template <class Event>
|
||||
class connection :
|
||||
public std::enable_shared_from_this<connection<Event>> {
|
||||
private:
|
||||
response_buffers& buffer_;
|
||||
net::steady_timer st_;
|
||||
tcp::resolver resv_;
|
||||
tcp::socket socket_;
|
||||
std::queue<request<Event>> reqs_;
|
||||
|
||||
template <class Receiver>
|
||||
net::awaitable<void>
|
||||
reconnect_loop(Receiver& recv)
|
||||
{
|
||||
try {
|
||||
auto ex = co_await net::this_coro::executor;
|
||||
auto const r = resv_.resolve("127.0.0.1", "6379");
|
||||
co_await async_connect(socket_, r, net::use_awaitable);
|
||||
resp::async_writer(socket_, reqs_, st_, net::detached);
|
||||
co_await co_spawn(
|
||||
ex,
|
||||
resp::async_reader(socket_, recv, reqs_),
|
||||
net::use_awaitable);
|
||||
} catch (std::exception const& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
socket_.close();
|
||||
st_.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
receiver_print(response_buffers& buffer)
|
||||
: buffer_{buffer}
|
||||
{}
|
||||
using event_type = Event;
|
||||
|
||||
// The ids in the queue parameter have an unspecified message type.
|
||||
template <class Event>
|
||||
void receive_transaction(std::queue<response_id<Event>> ids)
|
||||
connection(net::io_context& ioc)
|
||||
: st_{ioc}
|
||||
, resv_{ioc}
|
||||
, socket_{ioc}
|
||||
, reqs_ (resp::make_request_queue<Event>())
|
||||
{ }
|
||||
|
||||
template <class Receiver>
|
||||
void start(Receiver& recv)
|
||||
{
|
||||
while (!std::empty(ids)) {
|
||||
std::cout << ids.front() << std::endl;
|
||||
ids.pop();
|
||||
}
|
||||
net::co_spawn(
|
||||
socket_.get_executor(),
|
||||
[self = this->shared_from_this(), recv] () mutable { return self->reconnect_loop(recv); },
|
||||
net::detached);
|
||||
}
|
||||
|
||||
template <class Event>
|
||||
void receive(response_id<Event> const& id)
|
||||
{
|
||||
buffer_.tree().clear();
|
||||
template <class Filler>
|
||||
void send(Filler filler)
|
||||
{ queue_writer(reqs_, filler, st_); }
|
||||
|
||||
std::cout << id;
|
||||
switch (id.t) {
|
||||
case type::push:
|
||||
buffer_.push().clear();
|
||||
break;
|
||||
case type::set:
|
||||
buffer_.set().clear();
|
||||
break;
|
||||
case type::map:
|
||||
buffer_.map().clear();
|
||||
break;
|
||||
case type::attribute:
|
||||
buffer_.attribute().clear();
|
||||
break;
|
||||
case type::array:
|
||||
buffer_.array().clear();
|
||||
break;
|
||||
case type::simple_error:
|
||||
buffer_.simple_error().clear();
|
||||
break;
|
||||
case type::simple_string:
|
||||
buffer_.simple_string().clear();
|
||||
break;
|
||||
case type::number:
|
||||
break;
|
||||
case type::double_type:
|
||||
break;
|
||||
case type::big_number:
|
||||
buffer_.big_number().clear();
|
||||
break;
|
||||
case type::boolean:
|
||||
break;
|
||||
case type::blob_error:
|
||||
buffer_.blob_error().clear();
|
||||
break;
|
||||
case type::blob_string:
|
||||
buffer_.blob_string().clear();
|
||||
break;
|
||||
case type::verbatim_string:
|
||||
buffer_.verbatim_string().clear();
|
||||
break;
|
||||
case type::streamed_string_part:
|
||||
buffer_.streamed_string_part().clear();
|
||||
break;
|
||||
default:{}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
auto& requests() {return reqs_;}
|
||||
auto const& requests() const {return reqs_;}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -146,8 +146,9 @@ private:
|
||||
|
||||
void add(std::string_view s, type t)
|
||||
{
|
||||
assert(!std::empty(result));
|
||||
if (std::ssize(result.back().value) == result.back().expected_size) {
|
||||
if (std::empty(result)) {
|
||||
result.emplace_back(depth_, t, 1, std::vector<std::string>{std::string{s}});
|
||||
} else if (std::ssize(result.back().value) == result.back().expected_size) {
|
||||
result.emplace_back(depth_, t, 1, std::vector<std::string>{std::string{s}});
|
||||
} else {
|
||||
result.back().value.push_back(std::string{s});
|
||||
@@ -186,7 +187,8 @@ private:
|
||||
{ from_string_view(s, result); }
|
||||
|
||||
public:
|
||||
T result;
|
||||
using data_type = T;
|
||||
data_type result;
|
||||
};
|
||||
|
||||
using response_number = response_basic_number<long long int>;
|
||||
@@ -200,7 +202,8 @@ private:
|
||||
void on_blob_string_impl(std::string_view s) override
|
||||
{ from_string_view(s, result); }
|
||||
public:
|
||||
std::basic_string<CharT, Traits, Allocator> result;
|
||||
using data_type = std::basic_string<CharT, Traits, Allocator>;
|
||||
data_type result;
|
||||
};
|
||||
|
||||
using response_blob_string = response_basic_blob_string<char>;
|
||||
@@ -214,7 +217,8 @@ private:
|
||||
void on_blob_error_impl(std::string_view s) override
|
||||
{ from_string_view(s, result); }
|
||||
public:
|
||||
std::basic_string<CharT, Traits, Allocator> result;
|
||||
using data_type = std::basic_string<CharT, Traits, Allocator>;
|
||||
data_type result;
|
||||
};
|
||||
|
||||
using response_blob_error = response_basic_blob_error<char>;
|
||||
@@ -229,7 +233,8 @@ private:
|
||||
void on_simple_string_impl(std::string_view s) override
|
||||
{ from_string_view(s, result); }
|
||||
public:
|
||||
std::basic_string<CharT, Traits, Allocator> result;
|
||||
using data_type = std::basic_string<CharT, Traits, Allocator>;
|
||||
data_type result;
|
||||
};
|
||||
|
||||
using response_simple_string = response_basic_simple_string<char>;
|
||||
@@ -245,7 +250,8 @@ private:
|
||||
{ from_string_view(s, result); }
|
||||
|
||||
public:
|
||||
std::basic_string<CharT, Traits, Allocator> result;
|
||||
using data_type = std::basic_string<CharT, Traits, Allocator>;
|
||||
data_type result;
|
||||
};
|
||||
|
||||
using response_simple_error = response_basic_simple_error<char>;
|
||||
@@ -262,7 +268,8 @@ private:
|
||||
{ from_string_view(s, result); }
|
||||
|
||||
public:
|
||||
std::basic_string<CharT, Traits, Allocator> result;
|
||||
using data_type = std::basic_string<CharT, Traits, Allocator>;
|
||||
data_type result;
|
||||
};
|
||||
|
||||
using response_big_number = response_basic_big_number<char>;
|
||||
@@ -279,29 +286,12 @@ private:
|
||||
{ from_string_view(s, result); }
|
||||
|
||||
public:
|
||||
std::basic_string<CharT, Traits, Allocator> result;
|
||||
using data_type = std::basic_string<CharT, Traits, Allocator>;
|
||||
data_type result;
|
||||
};
|
||||
|
||||
using response_double = response_basic_double<char>;
|
||||
|
||||
template <
|
||||
class T,
|
||||
class Allocator = std::allocator<T>>
|
||||
class response_list : public response_base {
|
||||
private:
|
||||
void on_blob_string_impl(std::string_view s) override
|
||||
{
|
||||
T r;
|
||||
from_string_view(s, r);
|
||||
result.push_back(std::move(r));
|
||||
}
|
||||
|
||||
void select_array_impl(int n) override { }
|
||||
|
||||
public:
|
||||
std::list<T, Allocator> result;
|
||||
};
|
||||
|
||||
template<
|
||||
class CharT = char,
|
||||
class Traits = std::char_traits<CharT>,
|
||||
@@ -312,7 +302,8 @@ private:
|
||||
void on_verbatim_string_impl(std::string_view s) override
|
||||
{ from_string_view(s, result); }
|
||||
public:
|
||||
std::basic_string<CharT, Traits, Allocator> result;
|
||||
using data_type = std::basic_string<CharT, Traits, Allocator>;
|
||||
data_type result;
|
||||
};
|
||||
|
||||
using response_verbatim_string = response_basic_verbatim_string<char>;
|
||||
@@ -322,15 +313,16 @@ template<
|
||||
class Traits = std::char_traits<CharT>,
|
||||
class Allocator = std::allocator<CharT>
|
||||
>
|
||||
class response_basic_streamed_string : public response_base {
|
||||
class response_basic_streamed_string_part : public response_base {
|
||||
private:
|
||||
void on_streamed_string_part_impl(std::string_view s) override
|
||||
{ result += s; }
|
||||
public:
|
||||
std::basic_string<CharT, Traits, Allocator> result;
|
||||
using data_type = std::basic_string<CharT, Traits, Allocator>;
|
||||
data_type result;
|
||||
};
|
||||
|
||||
using response_streamed_string = response_basic_streamed_string<char>;
|
||||
using response_streamed_string_part = response_basic_streamed_string_part<char>;
|
||||
|
||||
template <
|
||||
class Key,
|
||||
@@ -367,7 +359,8 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
bool result;
|
||||
using data_type = bool;
|
||||
data_type result;
|
||||
};
|
||||
|
||||
template<
|
||||
@@ -395,7 +388,7 @@ template <
|
||||
class T,
|
||||
class Allocator = std::allocator<T>
|
||||
>
|
||||
class response_array : public response_base {
|
||||
class response_basic_array : public response_base {
|
||||
private:
|
||||
void add(std::string_view s = {})
|
||||
{
|
||||
@@ -419,14 +412,17 @@ private:
|
||||
void on_streamed_string_part_impl(std::string_view s = {}) override { add(s); }
|
||||
|
||||
public:
|
||||
std::vector<T, Allocator> result;
|
||||
using data_type = std::vector<T, Allocator>;
|
||||
data_type result;
|
||||
};
|
||||
|
||||
template <class T, class Allocator = std::allocator<T>>
|
||||
using response_flat_map = response_array<T, Allocator>;
|
||||
using response_array = response_basic_array<std::string>;
|
||||
|
||||
template <class T, class Allocator = std::allocator<T>>
|
||||
using response_flat_set = response_array<T, Allocator>;
|
||||
using response_flat_map = response_basic_array<T, Allocator>;
|
||||
|
||||
template <class T, class Allocator = std::allocator<T>>
|
||||
using response_flat_set = response_basic_array<T, Allocator>;
|
||||
|
||||
template <class T, std::size_t N>
|
||||
class response_static_array : public response_base {
|
||||
@@ -482,84 +478,27 @@ struct response_id {
|
||||
Event event;
|
||||
};
|
||||
|
||||
class response_buffers_ignore {
|
||||
private:
|
||||
response_ignore buf_;
|
||||
|
||||
public:
|
||||
template <class Event>
|
||||
response_base* get(response_id<Event> id) { return &buf_; }
|
||||
};
|
||||
|
||||
class response_buffers {
|
||||
private:
|
||||
// TODO: Use a variant to store all responses.
|
||||
response_tree tree_;
|
||||
|
||||
response_array<std::string> array_;
|
||||
response_array<std::string> push_;
|
||||
response_array<std::string> set_;
|
||||
response_array<std::string> map_;
|
||||
response_array<std::string> attribute_;
|
||||
response_array array_;
|
||||
response_array push_;
|
||||
response_array set_;
|
||||
response_array map_;
|
||||
response_array attribute_;
|
||||
response_simple_string simple_string_;
|
||||
response_simple_error simple_error_;
|
||||
response_number number_;
|
||||
response_double double_;
|
||||
response_bool boolean_;
|
||||
response_bool bool_;
|
||||
response_big_number big_number_;
|
||||
response_blob_string blob_string_;
|
||||
response_blob_error blob_error_;
|
||||
response_verbatim_string verbatim_string_;
|
||||
response_streamed_string streamed_string_part_;
|
||||
response_ignore ignore_;
|
||||
response_streamed_string_part streamed_string_part_;
|
||||
|
||||
public:
|
||||
auto& tree() {return tree_.result;};
|
||||
|
||||
auto& array() {return array_.result;};
|
||||
auto const& array() const noexcept {return array_.result;};
|
||||
|
||||
auto& push() {return push_.result;};
|
||||
auto const& push() const noexcept {return push_.result;};
|
||||
|
||||
auto& set() {return set_.result;};
|
||||
auto const& set() const noexcept {return set_.result;};
|
||||
|
||||
auto& map() {return map_.result;};
|
||||
auto const& map() const noexcept {return map_.result;};
|
||||
|
||||
auto& attribute() {return attribute_.result;};
|
||||
auto const& attribute() const noexcept {return attribute_.result;};
|
||||
|
||||
auto& simple_string() {return simple_string_.result;};
|
||||
auto const& simple_string() const noexcept {return simple_string_.result;};
|
||||
|
||||
auto& simple_error() {return simple_error_.result;};
|
||||
auto const& simple_error() const noexcept {return simple_error_.result;};
|
||||
|
||||
auto& number() {return number_.result;};
|
||||
auto const& number() const noexcept {return number_.result;};
|
||||
|
||||
auto& boolean() {return boolean_.result;};
|
||||
auto const& boolean() const noexcept {return boolean_.result;};
|
||||
|
||||
auto& double_type() {return double_.result;};
|
||||
auto const& double_type() const noexcept {return double_.result;};
|
||||
|
||||
auto& big_number() {return big_number_.result;};
|
||||
auto const& big_number() const noexcept {return big_number_.result;};
|
||||
|
||||
auto& blob_error() {return blob_error_.result;};
|
||||
auto const& blob_error() const noexcept {return blob_error_.result;};
|
||||
|
||||
auto& blob_string() {return blob_string_.result;};
|
||||
auto const& blob_string() const noexcept {return blob_string_.result;};
|
||||
|
||||
auto& verbatim_string() {return verbatim_string_.result;};
|
||||
auto const& verbatim_string() const noexcept {return verbatim_string_.result;};
|
||||
|
||||
auto& streamed_string_part() {return streamed_string_part_.result;};
|
||||
auto const& streamed_string_part() const noexcept {return streamed_string_part_.result;};
|
||||
|
||||
// When the id is from a transaction the type of the message is not
|
||||
// specified.
|
||||
template <class Event>
|
||||
@@ -579,12 +518,103 @@ public:
|
||||
case type::number: return &number_;
|
||||
case type::double_type: return &double_;
|
||||
case type::big_number: return &big_number_;
|
||||
case type::boolean: return &boolean_;
|
||||
case type::boolean: return &bool_;
|
||||
case type::blob_error: return &blob_error_;
|
||||
case type::blob_string: return &blob_string_;
|
||||
case type::verbatim_string: return &verbatim_string_;
|
||||
case type::streamed_string_part: return &streamed_string_part_;
|
||||
default: return &ignore_;
|
||||
default: {
|
||||
throw std::runtime_error("response_buffers");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <
|
||||
class Event,
|
||||
class Receiver>
|
||||
void
|
||||
forward_transaction(
|
||||
std::queue<response_id<Event>> ids,
|
||||
Receiver& recv)
|
||||
{
|
||||
while (!std::empty(ids)) {
|
||||
std::cout << ids.front() << std::endl;
|
||||
ids.pop();
|
||||
}
|
||||
|
||||
tree_.result.clear();
|
||||
}
|
||||
|
||||
template <
|
||||
class Event,
|
||||
class Receiver>
|
||||
void
|
||||
forward(
|
||||
response_id<Event> const& id,
|
||||
Receiver& recv)
|
||||
{
|
||||
// TODO: Handle null.
|
||||
switch (id.t) {
|
||||
case type::push:
|
||||
recv.on_push(id.cmd, id.event, push_.result);
|
||||
push_.result.clear();
|
||||
break;
|
||||
case type::set:
|
||||
recv.on_set(id.cmd, id.event, set_.result);
|
||||
set_.result.clear();
|
||||
break;
|
||||
case type::map:
|
||||
recv.on_map(id.cmd, id.event, map_.result);
|
||||
map_.result.clear();
|
||||
break;
|
||||
case type::attribute:
|
||||
recv.on_attribute(id.cmd, id.event, attribute_.result);
|
||||
attribute_.result.clear();
|
||||
break;
|
||||
case type::array:
|
||||
recv.on_array(id.cmd, id.event, array_.result);
|
||||
array_.result.clear();
|
||||
break;
|
||||
case type::simple_error:
|
||||
recv.on_simple_error(id.cmd, id.event, simple_error_.result);
|
||||
simple_error_.result.clear();
|
||||
break;
|
||||
case type::simple_string:
|
||||
recv.on_simple_string(id.cmd, id.event, simple_string_.result);
|
||||
simple_string_.result.clear();
|
||||
break;
|
||||
case type::number:
|
||||
recv.on_number(id.cmd, id.event, number_.result);
|
||||
break;
|
||||
case type::double_type:
|
||||
recv.on_double(id.cmd, id.event, double_.result);
|
||||
break;
|
||||
case type::big_number:
|
||||
recv.on_big_number(id.cmd, id.event, big_number_.result);
|
||||
big_number_.result.clear();
|
||||
break;
|
||||
case type::boolean:
|
||||
recv.on_boolean(id.cmd, id.event, bool_.result);
|
||||
bool_.result = false;
|
||||
break;
|
||||
case type::blob_error:
|
||||
recv.on_blob_error(id.cmd, id.event, blob_error_.result);
|
||||
blob_error_.result.clear();
|
||||
break;
|
||||
case type::blob_string:
|
||||
recv.on_blob_string(id.cmd, id.event, blob_string_.result);
|
||||
blob_string_.result.clear();
|
||||
break;
|
||||
case type::verbatim_string:
|
||||
recv.on_verbatim_string(id.cmd, id.event, verbatim_string_.result);
|
||||
verbatim_string_.result.clear();
|
||||
break;
|
||||
case type::streamed_string_part:
|
||||
recv.on_streamed_string_part(id.cmd, id.event, streamed_string_part_.result);
|
||||
streamed_string_part_.result.clear();
|
||||
break;
|
||||
default:{}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -599,7 +629,7 @@ operator<<(std::ostream& os, aedis::resp::response_id<Event> const& id)
|
||||
os
|
||||
<< std::left << std::setw(15) << aedis::resp::to_string(id.cmd)
|
||||
<< std::left << std::setw(20) << aedis::resp::to_string(id.t)
|
||||
<< std::left << std::setw(20) << (int)id.event
|
||||
<< std::left << std::setw(4) << (int)id.event
|
||||
;
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -14,19 +14,36 @@ namespace aedis { namespace resp {
|
||||
template <class Iter>
|
||||
void print(Iter begin, Iter end, char const* p)
|
||||
{
|
||||
std::cout << p << ": ";
|
||||
if (p)
|
||||
std::cout << p << ": ";
|
||||
for (; begin != end; ++begin)
|
||||
std::cout << *begin << " ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
void print(Range const& v, char const* p = "")
|
||||
void print(Range const& v, char const* p = nullptr)
|
||||
{
|
||||
using std::cbegin;
|
||||
using std::cend;
|
||||
print(cbegin(v), cend(v), p);
|
||||
}
|
||||
|
||||
inline
|
||||
void print_command_raw(std::string const& data, int n)
|
||||
{
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (data[i] == '\n') {
|
||||
std::cout << "\\n";
|
||||
continue;
|
||||
}
|
||||
if (data[i] == '\r') {
|
||||
std::cout << "\\r";
|
||||
continue;
|
||||
}
|
||||
std::cout << data[i];
|
||||
}
|
||||
}
|
||||
|
||||
} // resp
|
||||
} // aedis
|
||||
|
||||
Reference in New Issue
Block a user