From 34838f8323d4a9521ea8702e403dc999b465f755 Mon Sep 17 00:00:00 2001 From: Ruben Perez Date: Wed, 21 Jan 2026 21:42:48 +0100 Subject: [PATCH] Initial impl --- example/cpp20_subscriber.cpp | 16 +++- include/boost/redis/resp3/flat_tree.hpp | 8 ++ .../boost/redis/resp3/impl/messages_view.ipp | 27 ++++++ include/boost/redis/resp3/messages_view.hpp | 91 +++++++++++++++++++ include/boost/redis/src.hpp | 1 + 5 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 include/boost/redis/resp3/impl/messages_view.ipp create mode 100644 include/boost/redis/resp3/messages_view.hpp diff --git a/example/cpp20_subscriber.cpp b/example/cpp20_subscriber.cpp index 513f90ac..ff3745e3 100644 --- a/example/cpp20_subscriber.cpp +++ b/example/cpp20_subscriber.cpp @@ -5,6 +5,8 @@ */ #include +#include +#include #include #include @@ -14,10 +16,12 @@ #include #include +#include #if defined(BOOST_ASIO_HAS_CO_AWAIT) namespace asio = boost::asio; +namespace resp3 = boost::redis::resp3; using namespace std::chrono_literals; using boost::redis::request; using boost::redis::generic_flat_response; @@ -72,10 +76,14 @@ auto receiver(std::shared_ptr conn) -> asio::awaitable // The response must be consumed without suspending the // coroutine i.e. without the use of async operations. - for (auto const& elem : resp.value()) - std::cout << elem.value << "\n"; - - std::cout << std::endl; + for (std::span message : resp.value().messages()) { + if ( + message.size() == 4u && message[0].data_type == resp3::type::push && + message[1].value == "message") { + std::cout << "Channel: " << message[2].value << ", message: " << message[3].value + << "\n"; + } + } resp.value().clear(); } diff --git a/include/boost/redis/resp3/flat_tree.hpp b/include/boost/redis/resp3/flat_tree.hpp index 2783e9ad..5f125208 100644 --- a/include/boost/redis/resp3/flat_tree.hpp +++ b/include/boost/redis/resp3/flat_tree.hpp @@ -9,6 +9,7 @@ #ifndef BOOST_REDIS_RESP3_FLAT_TREE_HPP #define BOOST_REDIS_RESP3_FLAT_TREE_HPP +#include #include #include @@ -354,6 +355,13 @@ class flat_tree { */ std::size_t get_total_msgs() const noexcept { return total_msgs_; } + messages_view messages() const noexcept + { + return messages_view{ + {begin(), end()} + }; + } + private: template friend class adapter::detail::general_aggregate; diff --git a/include/boost/redis/resp3/impl/messages_view.ipp b/include/boost/redis/resp3/impl/messages_view.ipp new file mode 100644 index 00000000..b9dca10a --- /dev/null +++ b/include/boost/redis/resp3/impl/messages_view.ipp @@ -0,0 +1,27 @@ +// +// Copyright (c) 2026 Marcelo Zimbres Silva (mzimbres@gmail.com), +// Ruben Perez Hidalgo (rubenperez038 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) +// + +#include +#include + +#include +#include + +namespace boost::redis::resp3 { + +std::size_t messages_view::compute_message_size(span messages) +{ + if (messages.empty()) + return 0u; + auto it = std::find_if(messages.begin() + 1u, messages.end(), [](const resp3::node_view& n) { + return n.depth == 0u; + }); + return it - messages.begin(); +} + +} // namespace boost::redis::resp3 diff --git a/include/boost/redis/resp3/messages_view.hpp b/include/boost/redis/resp3/messages_view.hpp new file mode 100644 index 00000000..870a59c9 --- /dev/null +++ b/include/boost/redis/resp3/messages_view.hpp @@ -0,0 +1,91 @@ +// +// Copyright (c) 2026 Marcelo Zimbres Silva (mzimbres@gmail.com), +// Ruben Perez Hidalgo (rubenperez038 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 BOOST_REDIS_RESP3_MESSAGES_VIEW_HPP +#define BOOST_REDIS_RESP3_MESSAGES_VIEW_HPP + +#include + +#include + +#include +#include + +namespace boost::redis::resp3 { + +class messages_view { + span nodes_; + + static std::size_t compute_message_size(span nodes); + +public: + // TODO: explicit? + messages_view(span nodes) noexcept + : nodes_{nodes} + { } + + class iterator { + const node_view* data_; + const node_view* end_; // required to iterate + std::size_t size_; // of the found range + + friend class messages_view; + + iterator(const node_view* data, const node_view* end, std::size_t size) noexcept + : data_{data} + , end_{end} + , size_{size} + { } + + void increment() + { + data_ += size_; + size_ = compute_message_size({data_, end_}); + } + + public: + using value_type = span; + using reference = span; + using pointer = span; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + iterator() = default; + + reference operator*() const noexcept { return {data_, size_}; } + + pointer operator->() const noexcept { return {data_, size_}; } + + iterator& operator++() noexcept + { + increment(); + return *this; + } + + iterator operator++(int) noexcept + { + iterator res{*this}; + increment(); + return res; + } + + bool operator==(const iterator& rhs) const noexcept { return data_ == rhs.data_; } + bool operator!=(const iterator& rhs) const noexcept { return !(*this == rhs); } + }; + + iterator begin() const noexcept + { + return {nodes_.begin(), nodes_.end(), compute_message_size(nodes_)}; + } + iterator end() const noexcept { return {nodes_.end(), nodes_.end(), 0u}; } + bool empty() const noexcept { return nodes_.empty(); } +}; + +} // namespace boost::redis::resp3 + +#endif // BOOST_REDIS_RESP3_FLAT_TREE_HPP diff --git a/include/boost/redis/src.hpp b/include/boost/redis/src.hpp index 196b2960..0f3a4d4b 100644 --- a/include/boost/redis/src.hpp +++ b/include/boost/redis/src.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include