Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🎨 Allow indexed handler to handle messages by value #615

Merged
merged 1 commit into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 13 additions & 16 deletions include/msg/detail/indexed_builder_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,28 +127,26 @@ template <typename... Fields>
using index_spec = decltype(stdx::make_indexed_tuple<get_field_type>(
temp_index<Fields, 512, 256>{}...));

template <template <typename, typename, typename, typename...> typename ParentT,
typename IndexSpec, typename CallbacksT, typename BaseMsgT,
typename... ExtraCallbackArgsT>
template <template <typename, typename, typename, typename...> typename Parent,
typename IndexSpec, typename Callbacks, typename MsgBase,
typename... ExtraCallbackArgs>
struct indexed_builder_base {
CallbacksT callbacks;
Callbacks callbacks;

template <typename... Ts> [[nodiscard]] constexpr auto add(Ts... ts) {
auto new_callbacks =
stdx::tuple_cat(callbacks, separate_sum_terms(ts)...);
using new_callbacks_t = decltype(new_callbacks);
return ParentT<IndexSpec, new_callbacks_t, BaseMsgT,
ExtraCallbackArgsT...>{new_callbacks};
return Parent<IndexSpec, new_callbacks_t, MsgBase,
ExtraCallbackArgs...>{new_callbacks};
}

using callback_func_t = auto (*)(BaseMsgT const &,
ExtraCallbackArgsT... args) -> bool;
using callback_func_t = auto (*)(MsgBase const &,
ExtraCallbackArgs... args) -> bool;

template <typename BuilderValue, std::size_t I>
constexpr static auto invoke_callback(BaseMsgT const &data,
ExtraCallbackArgsT... args) -> bool {
// FIXME: incomplete message callback invocation...
// 1) bit_cast message argument
constexpr static auto invoke_callback(MsgBase const &data,
ExtraCallbackArgs... args) -> bool {
constexpr auto cb = IndexSpec{}.apply([&]<typename... Indices>(
Indices...) {
constexpr auto orig_cb =
Expand All @@ -164,15 +162,14 @@ struct indexed_builder_base {
"Indexed callback has matcher that is never matched!");
}

auto view = typename CB::msg_t::view_t{data};

if (cb.matcher(view)) {
using msg_t = typename CB::msg_t;
if (msg::call_with_message<msg_t>(cb.matcher, data)) {
CIB_INFO(
"Incoming message matched [{}], because [{}] (collapsed to "
"[{}]), executing callback",
stdx::ct_string_to_type<cb.name, sc::string_constant>(),
orig_cb.matcher.describe(), cb.matcher.describe());
cb.callable(view, args...);
msg::call_with_message<msg_t>(cb.callable, data, args...);
return true;
}
return false;
Expand Down
43 changes: 25 additions & 18 deletions include/msg/detail/indexed_handler_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@

#include <log/log.hpp>
#include <msg/handler_interface.hpp>
#include <msg/message.hpp>

#include <stdx/compiler.hpp>
#include <stdx/ranges.hpp>

#include <iterator>
#include <type_traits>
#include <utility>

namespace msg {

template <typename Field, typename Lookup> struct index {
Expand All @@ -23,30 +28,25 @@ template <typename Field, typename Lookup> struct index {
}
};

template <typename BaseMsgT, typename... ExtraCallbackArgsT>
struct callback_args_t {};

template <typename BaseMsgT, typename... ExtraCallbackArgsT>
constexpr callback_args_t<BaseMsgT, ExtraCallbackArgsT...> callback_args{};
template <typename Index, typename Callbacks, typename MsgBase,
typename... ExtraCallbackArgs>
struct indexed_handler : handler_interface<MsgBase, ExtraCallbackArgs...> {
Index index;
Callbacks callback_entries;

template <typename IndexT, typename CallbacksT, typename BaseMsgT,
typename... ExtraCallbackArgsT>
struct indexed_handler : handler_interface<BaseMsgT, ExtraCallbackArgsT...> {
IndexT index;
CallbacksT callback_entries;
template <typename Idx, typename CBs>
constexpr explicit indexed_handler(Idx &&idx, CBs &&cbs)
: index{std::forward<Idx>(idx)},
callback_entries{std::forward<CBs>(cbs)} {}

constexpr explicit indexed_handler(
callback_args_t<BaseMsgT, ExtraCallbackArgsT...>, IndexT new_index,
CallbacksT new_callbacks)
: index{new_index}, callback_entries{new_callbacks} {}

auto is_match(BaseMsgT const &msg) const -> bool final {
// This function may lie... it may claim to match when it doesn't because
// there are further conditions on the non-indexed parts of the matcher
auto is_match(MsgBase const &msg) const -> bool final {
return not index(msg).none();
}

__attribute__((flatten)) auto
handle(BaseMsgT const &msg,
ExtraCallbackArgsT... args) const -> bool final {
handle(MsgBase const &msg, ExtraCallbackArgs... args) const -> bool final {
auto const callback_candidates = index(msg);

bool handled{};
Expand All @@ -60,4 +60,11 @@ struct indexed_handler : handler_interface<BaseMsgT, ExtraCallbackArgsT...> {
}
};

template <typename MsgBase, typename... ExtraCallbackArgs>
constexpr auto make_indexed_handler = []<typename Idx, typename CBs>(
Idx &&idx, CBs &&cbs) {
return indexed_handler<std::remove_cvref_t<Idx>, std::remove_cvref_t<CBs>,
MsgBase, ExtraCallbackArgs...>{
std::forward<Idx>(idx), std::forward<CBs>(cbs)};
};
} // namespace msg
8 changes: 4 additions & 4 deletions include/msg/handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@

namespace msg {

template <typename Callbacks, typename BaseMsg, typename... ExtraCallbackArgs>
struct handler : handler_interface<BaseMsg, ExtraCallbackArgs...> {
template <typename Callbacks, typename MsgBase, typename... ExtraCallbackArgs>
struct handler : handler_interface<MsgBase, ExtraCallbackArgs...> {
Callbacks callbacks{};

constexpr explicit handler(Callbacks new_callbacks)
: callbacks{new_callbacks} {}

auto is_match(BaseMsg const &msg) const -> bool final {
auto is_match(MsgBase const &msg) const -> bool final {
return stdx::any_of(
[&](auto &callback) { return callback.is_match(msg); }, callbacks);
}

auto handle(BaseMsg const &msg,
auto handle(MsgBase const &msg,
ExtraCallbackArgs... args) const -> bool final {
auto const found_valid_callback = stdx::apply(
[&](auto &...cbs) -> bool {
Expand Down
11 changes: 5 additions & 6 deletions include/msg/handler_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,20 @@
#include <stdx/tuple_algorithms.hpp>

namespace msg {
template <typename CallbacksT, typename BaseMsgT,
typename... ExtraCallbackArgsT>
template <typename Callbacks, typename MsgBase, typename... ExtraCallbackArgs>
struct handler_builder {
CallbacksT callbacks;
Callbacks callbacks;

template <typename... Ts> [[nodiscard]] constexpr auto add(Ts... ts) {
auto new_callbacks =
stdx::tuple_cat(callbacks, stdx::make_tuple(ts...));
using new_callbacks_t = decltype(new_callbacks);
return handler_builder<new_callbacks_t, BaseMsgT,
ExtraCallbackArgsT...>{new_callbacks};
return handler_builder<new_callbacks_t, MsgBase, ExtraCallbackArgs...>{
new_callbacks};
}

template <typename BuilderValue> constexpr static auto build() {
return handler<CallbacksT, BaseMsgT, ExtraCallbackArgsT...>{
return handler<Callbacks, MsgBase, ExtraCallbackArgs...>{
BuilderValue::value.callbacks};
}
};
Expand Down
8 changes: 4 additions & 4 deletions include/msg/handler_interface.hpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#pragma once

namespace msg {
template <typename MsgBaseT, typename... ExtraCallbackArgsT>
template <typename MsgBase, typename... ExtraCallbackArgs>
struct handler_interface {
virtual auto is_match(MsgBaseT const &msg) const -> bool = 0;
virtual auto is_match(MsgBase const &msg) const -> bool = 0;

virtual auto handle(MsgBaseT const &msg,
ExtraCallbackArgsT... extra_args) const -> bool = 0;
virtual auto handle(MsgBase const &msg,
ExtraCallbackArgs... extra_args) const -> bool = 0;
};
} // namespace msg
24 changes: 11 additions & 13 deletions include/msg/indexed_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@

namespace msg {
// TODO: needs index configuration
template <typename IndexSpec, typename CallbacksT, typename BaseMsgT,
typename... ExtraCallbackArgsT>
template <typename IndexSpec, typename Callbacks, typename MsgBase,
typename... ExtraCallbackArgs>
struct indexed_builder
: indexed_builder_base<indexed_builder, IndexSpec, CallbacksT, BaseMsgT,
ExtraCallbackArgsT...> {
using base_t = indexed_builder_base<indexed_builder, IndexSpec, CallbacksT,
BaseMsgT, ExtraCallbackArgsT...>;
: indexed_builder_base<indexed_builder, IndexSpec, Callbacks, MsgBase,
ExtraCallbackArgs...> {
using base_t = indexed_builder_base<indexed_builder, IndexSpec, Callbacks,
MsgBase, ExtraCallbackArgs...>;

template <typename I, auto E>
static CONSTEVAL auto get_entry(auto const &indices) {
Expand Down Expand Up @@ -73,14 +73,12 @@ struct indexed_builder
});

constexpr auto num_callbacks = BuilderValue::value.callbacks.size();
constexpr std::array<typename base_t::callback_func_t, num_callbacks>
callback_array =
base_t::template create_callback_array<BuilderValue>(
std::make_index_sequence<num_callbacks>{});
constexpr auto callback_array =
base_t::template create_callback_array<BuilderValue>(
std::make_index_sequence<num_callbacks>{});

return indexed_handler{
callback_args_t<BaseMsgT, ExtraCallbackArgsT...>{}, baked_indices,
callback_array};
return make_indexed_handler<MsgBase, ExtraCallbackArgs...>(
baked_indices, callback_array);
}
};

Expand Down
8 changes: 4 additions & 4 deletions include/msg/indexed_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

namespace msg {

template <typename... IndicesT> struct indices : IndicesT... {
CONSTEVAL explicit indices(IndicesT... index_args)
: IndicesT{index_args}... {}
template <typename... Indices> struct indices : Indices... {
CONSTEVAL explicit indices(Indices... index_args)
: Indices{index_args}... {}

constexpr auto operator()(auto const &data) const {
return (this->IndicesT::operator()(data) & ...);
return (this->Indices::operator()(data) & ...);
}
};

Expand Down
8 changes: 4 additions & 4 deletions include/msg/indexed_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
#include <stdx/tuple.hpp>

namespace msg {
template <typename IndexSpec, typename MsgBaseT, typename... ExtraCallbackArgsT>
template <typename IndexSpec, typename MsgBase, typename... ExtraCallbackArgs>
struct indexed_service
: cib::builder_meta<
indexed_builder<IndexSpec, stdx::tuple<>, MsgBaseT,
ExtraCallbackArgsT...>,
handler_interface<MsgBaseT, ExtraCallbackArgsT...> const *> {};
indexed_builder<IndexSpec, stdx::tuple<>, MsgBase,
ExtraCallbackArgs...>,
handler_interface<MsgBase, ExtraCallbackArgs...> const *> {};
} // namespace msg
4 changes: 2 additions & 2 deletions include/msg/message.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -629,8 +629,8 @@ constexpr auto equivalent(O1 const &lhs, O2 const &rhs) {
}

template <typename Msg, typename F, typename S, typename... Args>
constexpr auto call_with_message(F &&f, S &&s,
Args &&...args) -> decltype(auto) {
__attribute__((flatten, always_inline)) constexpr auto
call_with_message(F &&f, S &&s, Args &&...args) -> decltype(auto) {
if constexpr (requires {
std::forward<F>(f)(std::forward<S>(s),
std::forward<Args>(args)...);
Expand Down
6 changes: 3 additions & 3 deletions include/msg/service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
#include <stdx/tuple.hpp>

namespace msg {
template <typename MsgBaseT, typename... ExtraCallbackArgsT>
template <typename MsgBase, typename... ExtraCallbackArgs>
struct service
: cib::builder_meta<
handler_builder<stdx::tuple<>, MsgBaseT, ExtraCallbackArgsT...>,
handler_interface<MsgBaseT, ExtraCallbackArgsT...> const *> {};
handler_builder<stdx::tuple<>, MsgBase, ExtraCallbackArgs...>,
handler_interface<MsgBase, ExtraCallbackArgs...> const *> {};
} // namespace msg
68 changes: 67 additions & 1 deletion test/msg/indexed_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ using msg_defn = message<"test_msg", test_id_field, test_opcode_field,
test_field_2, test_field_3>;
using test_msg_t = owning<msg_defn>;

using index_spec = index_spec<test_id_field, test_opcode_field>;
using index_spec = msg::index_spec<test_id_field, test_opcode_field>;
struct test_service : indexed_service<index_spec, test_msg_t> {};

bool callback_success;
Expand Down Expand Up @@ -423,3 +423,69 @@ TEST_CASE("handle extra arguments", "[indexed_builder]") {
CHECK(callback_success);
CHECK(callback_extra_arg == 42);
}

namespace {
using base_storage_t = msg_defn::default_storage_t;
struct raw_service : indexed_service<index_spec, base_storage_t> {};

int callback_count{};

constexpr auto raw_view_callback = callback<"raw view", msg_defn>(
msg::in<test_id_field, 0x80>,
[](msg::const_view<msg_defn>) { ++callback_count; });

struct raw_view_project {
constexpr static auto config = cib::config(
cib::exports<raw_service>, cib::extend<raw_service>(raw_view_callback));
};
} // namespace

TEST_CASE("handle raw message by view", "[indexed_builder]") {
cib::nexus<raw_view_project> test_nexus{};
test_nexus.init();

callback_count = 0;
CHECK(cib::service<raw_service>->handle(
std::array{0x8000ba11u, 0x0042d00du}));
CHECK(callback_count == 1);
}

namespace {
constexpr auto raw_owning_callback = callback<"raw owning", msg_defn>(
msg::in<test_id_field, 0x80>,
[](msg::owning<msg_defn>) { ++callback_count; });

struct raw_owning_project {
constexpr static auto config =
cib::config(cib::exports<raw_service>,
cib::extend<raw_service>(raw_owning_callback));
};
} // namespace

TEST_CASE("handle raw message by owning", "[indexed_builder]") {
cib::nexus<raw_owning_project> test_nexus{};
test_nexus.init();

callback_count = 0;
CHECK(cib::service<raw_service>->handle(
std::array{0x8000ba11u, 0x0042d00du}));
CHECK(callback_count == 1);
}

namespace {
struct raw_mixed_project {
constexpr static auto config = cib::config(
cib::exports<raw_service>,
cib::extend<raw_service>(raw_view_callback, raw_owning_callback));
};
} // namespace

TEST_CASE("handle raw message by mixture of callbacks", "[indexed_builder]") {
cib::nexus<raw_mixed_project> test_nexus{};
test_nexus.init();

callback_count = 0;
CHECK(cib::service<raw_service>->handle(
std::array{0x8000ba11u, 0x0042d00du}));
CHECK(callback_count == 2);
}
Loading