diff --git a/include/msg/field.hpp b/include/msg/field.hpp index 557c251c..e332330e 100644 --- a/include/msg/field.hpp +++ b/include/msg/field.hpp @@ -532,5 +532,8 @@ struct field { using located = detail::field_t< decltype(stdx::ct_string_to_type()), T, Default, M, Ats...>; + + constexpr static auto bitsize = sizeof(T) * CHAR_BIT; + using default_located = located; }; } // namespace msg diff --git a/include/msg/message.hpp b/include/msg/message.hpp index 943e90ab..3404632f 100644 --- a/include/msg/message.hpp +++ b/include/msg/message.hpp @@ -664,15 +664,12 @@ namespace detail { template using msg_sizes = stdx::type_list...>; -template -using negated_size = std::integral_constant; - template -using msg_offsets = boost::mp11::mp_partial_sum< - msg_sizes, - negated_size>::template size>, - boost::mp11::mp_plus>; +using msg_offsets = boost::mp11::mp_push_front< + boost::mp11::mp_partial_sum, + std::integral_constant, + boost::mp11::mp_plus>, + std::integral_constant>; template struct shift_msg_q { template @@ -680,9 +677,10 @@ template struct shift_msg_q { }; template -using shifted_msgs = boost::mp11::mp_transform_q, - msg_offsets, - stdx::type_list>; +using shifted_msgs = + boost::mp11::mp_transform_q, + msg_offsets, + stdx::type_list>>; template struct combiner { template using fn = msg::message; @@ -704,4 +702,40 @@ template requires(sizeof...(Msgs) > 0) using pack = boost::mp11::mp_apply_q, detail::shifted_msgs>; + +namespace detail { +template +using is_locatable = std::bool_constant; + +template +using field_size_sort_fn = std::bool_constant < F2::bitsize; + +template struct field_locator { + using fields = boost::mp11::mp_partition, + is_locatable>; + using located_fields = boost::mp11::mp_first; + using unlocated_fields = boost::mp11::mp_second; + + using located_msg = boost::mp11::mp_apply_q, located_fields>; + + using auto_fields = + boost::mp11::mp_sort; + + template + using as_singleton_message = + msg::message; + using auto_msgs = + boost::mp11::mp_transform; + + using all_msgs = boost::mp11::mp_push_front; + + template + using pack = msg::pack; + using msg_type = boost::mp11::mp_apply; +}; +} // namespace detail + +template +using relaxed_message = + typename detail::field_locator::msg_type; } // namespace msg diff --git a/test/msg/CMakeLists.txt b/test/msg/CMakeLists.txt index 61c06d4a..b77b0370 100644 --- a/test/msg/CMakeLists.txt +++ b/test/msg/CMakeLists.txt @@ -12,6 +12,7 @@ add_tests( indexed_handler indexed_handler_uninit message + relaxed_message send LIBRARIES cib) diff --git a/test/msg/message.cpp b/test/msg/message.cpp index e7cb5bc7..9958de90 100644 --- a/test/msg/message.cpp +++ b/test/msg/message.cpp @@ -621,3 +621,24 @@ TEST_CASE("pack 1 message", "[message]") { using expected_defn = message<"defn", f1, f2>; static_assert(std::is_same_v); } + +TEST_CASE("pack with empty messages", "[message]") { + using m0 = message<"m0">; + + using f1 = field<"f1", std::uint32_t>::located; + using f2 = field<"f2", std::uint32_t>::located; + using m1 = message<"m1", f1, f2>; + + using m2 = message<"m2">; + + using f3 = field<"f3", std::uint32_t>::located; + using f4 = field<"f4", std::uint32_t>::located; + using m3 = message<"m3", f3, f4>; + + using defn = pack<"defn", std::uint8_t, m0, m1, m2, m3>; + using expected_defn = + message<"defn", f1, f2, + f3::shifted_by::value, std::uint8_t>, + f4::shifted_by::value, std::uint8_t>>; + static_assert(std::is_same_v); +} diff --git a/test/msg/relaxed_message.cpp b/test/msg/relaxed_message.cpp new file mode 100644 index 00000000..06ed11d4 --- /dev/null +++ b/test/msg/relaxed_message.cpp @@ -0,0 +1,45 @@ +#include + +#include + +namespace { +using namespace msg; + +using fixed_f = + field<"fixed", std::uint32_t>::located; +using auto_f1 = field<"auto1", std::uint32_t>; +using auto_f2 = field<"auto2", std::uint8_t>; + +} // namespace + +TEST_CASE("message with automatically packed fields", "[relaxed_message]") { + using defn = relaxed_message<"msg", auto_f1, auto_f2>; + using expected_defn = + msg::message<"msg", auto_f1::located, + auto_f2::located>; + static_assert(std::is_same_v); +} + +TEST_CASE("automatically packed fields are sorted by size", + "[relaxed_message]") { + using defn = relaxed_message<"msg", auto_f2, auto_f1>; + using expected_defn = + msg::message<"msg", auto_f1::located, + auto_f2::located>; + static_assert(std::is_same_v); +} + +TEST_CASE("message with mixed fixed and automatically packed fields", + "[relaxed_message]") { + using defn = relaxed_message<"msg", auto_f2, fixed_f, auto_f1>; + using expected_defn = + msg::message<"msg", fixed_f, auto_f1::located, + auto_f2::located>; + static_assert(std::is_same_v); +} + +TEST_CASE("message with no automatically packed fields", "[relaxed_message]") { + using defn = relaxed_message<"msg", fixed_f>; + using expected_defn = msg::message<"msg", fixed_f>; + static_assert(std::is_same_v); +}