|
4 | 4 | #include <log/catalog/mipi_messages.hpp>
|
5 | 5 |
|
6 | 6 | #include <stdx/compiler.hpp>
|
| 7 | +#include <stdx/type_traits.hpp> |
7 | 8 | #include <stdx/utility.hpp>
|
8 | 9 |
|
9 | 10 | #include <array>
|
|
13 | 14 | #include <utility>
|
14 | 15 |
|
15 | 16 | namespace logging::mipi {
|
| 17 | +template <typename T> |
| 18 | +concept signed_packable = |
| 19 | + std::signed_integral<T> and sizeof(T) <= sizeof(std::int64_t); |
| 20 | + |
| 21 | +template <typename T> |
| 22 | +concept unsigned_packable = |
| 23 | + std::unsigned_integral<T> and sizeof(T) <= sizeof(std::int64_t); |
| 24 | + |
| 25 | +template <typename T> |
| 26 | +concept enum_packable = std::is_enum_v<T> and sizeof(T) <= sizeof(std::int64_t); |
| 27 | + |
| 28 | +template <typename T> |
| 29 | +concept packable = |
| 30 | + signed_packable<T> or unsigned_packable<T> or enum_packable<T>; |
| 31 | + |
| 32 | +template <typename T> struct pack_as; |
| 33 | + |
| 34 | +template <signed_packable T> struct pack_as<T> { |
| 35 | + using type = |
| 36 | + // NOLINTNEXTLINE(google-runtime-int) |
| 37 | + stdx::conditional_t<sizeof(T) <= sizeof(std::int32_t), int, long long>; |
| 38 | +}; |
| 39 | + |
| 40 | +template <unsigned_packable T> struct pack_as<T> { |
| 41 | + using type = stdx::conditional_t<sizeof(T) <= sizeof(std::int32_t), |
| 42 | + // NOLINTNEXTLINE(google-runtime-int) |
| 43 | + unsigned int, unsigned long long>; |
| 44 | +}; |
| 45 | + |
| 46 | +template <enum_packable T> |
| 47 | + requires(sizeof(T) <= sizeof(std::int32_t)) |
| 48 | +struct pack_as<T> : pack_as<stdx::underlying_type_t<T>> {}; |
| 49 | + |
| 50 | +template <packable T> using pack_as_t = typename pack_as<T>::type; |
| 51 | + |
16 | 52 | template <typename> struct builder;
|
17 | 53 |
|
18 | 54 | template <> struct builder<defn::short32_msg_t> {
|
19 |
| - template <auto Level, std::same_as<std::uint32_t>... Ts> |
20 |
| - static auto build(string_id id, module_id, Ts...) { |
| 55 | + template <auto Level> static auto build(string_id id, module_id) { |
21 | 56 | using namespace msg;
|
22 | 57 | return owning<defn::short32_msg_t>{"payload"_field = id};
|
23 | 58 | }
|
24 | 59 | };
|
25 | 60 |
|
26 | 61 | template <typename Storage> struct catalog_builder {
|
27 |
| - template <auto Level, std::same_as<std::uint32_t>... Ts> |
28 |
| - static auto build(string_id id, module_id m, Ts... msg_data) { |
| 62 | + template <auto Level, packable... Ts> |
| 63 | + static auto build(string_id id, module_id m, Ts... args) { |
29 | 64 | using namespace msg;
|
30 | 65 | defn::catalog_msg_t::owner_t<Storage> message{"severity"_field = Level,
|
31 | 66 | "module_id"_field = m};
|
32 | 67 |
|
33 | 68 | constexpr auto header_size =
|
34 | 69 | defn::catalog_msg_t::size<typename Storage::value_type>::value;
|
35 |
| - constexpr auto copy_arg = [](std::uint32_t arg, auto &dest) { |
36 |
| - std::memcpy(dest, &arg, sizeof(std::uint32_t)); |
37 |
| - dest += sizeof(std::uint32_t); |
38 |
| - }; |
39 |
| - auto dest = &message.data()[header_size]; |
40 |
| - copy_arg(stdx::to_le(id), dest); |
41 |
| - (copy_arg(stdx::to_le(msg_data), dest), ...); |
42 |
| - |
43 |
| - return message; |
44 |
| - } |
45 |
| -}; |
46 | 70 |
|
47 |
| -template <typename Storage> |
48 |
| - requires std::same_as<typename Storage::value_type, std::uint32_t> |
49 |
| -struct catalog_builder<Storage> { |
50 |
| - template <auto Level, std::same_as<std::uint32_t>... Ts> |
51 |
| - static auto build(string_id id, module_id m, Ts... msg_data) { |
52 |
| - using namespace msg; |
53 |
| - defn::catalog_msg_t::owner_t<Storage> message{"severity"_field = Level, |
54 |
| - "module_id"_field = m}; |
| 71 | + using V = Storage::value_type; |
| 72 | + auto const pack_arg = []<typename T>(V *p, T arg) -> V * { |
| 73 | + auto const packed = stdx::to_le(stdx::as_unsigned( |
| 74 | + static_cast<pack_as_t<T>>(stdx::to_underlying(arg)))); |
| 75 | + std::memcpy(p, &packed, sizeof(packed)); |
| 76 | + return p + stdx::sized8{sizeof(packed)}.in<V>(); |
| 77 | + }; |
55 | 78 |
|
56 |
| - constexpr auto header_size = |
57 |
| - defn::catalog_msg_t::size<std::uint32_t>::value; |
58 | 79 | auto dest = &message.data()[header_size];
|
59 |
| - *dest++ = stdx::to_le(id); |
60 |
| - ((*dest++ = stdx::to_le(msg_data)), ...); |
| 80 | + dest = pack_arg(dest, stdx::to_le(id)); |
| 81 | + ((dest = pack_arg(dest, args)), ...); |
61 | 82 |
|
62 | 83 | return message;
|
63 | 84 | }
|
64 | 85 | };
|
65 | 86 |
|
66 | 87 | template <> struct builder<defn::catalog_msg_t> {
|
67 |
| - template <auto Level, std::same_as<std::uint32_t>... Ts> |
68 |
| - static auto build(string_id id, module_id m, Ts... msg_data) { |
| 88 | + template <auto Level, typename... Ts> |
| 89 | + static auto build(string_id id, module_id m, Ts... args) { |
69 | 90 | using namespace msg;
|
70 |
| - if constexpr (sizeof...(Ts) <= 2u) { |
| 91 | + if constexpr ((0 + ... + sizeof(Ts)) <= sizeof(std::uint32_t) * 2) { |
71 | 92 | constexpr auto header_size =
|
72 | 93 | defn::catalog_msg_t::size<std::uint32_t>::value;
|
73 |
| - constexpr auto payload_len = 1 + sizeof...(Ts); |
| 94 | + constexpr auto payload_size = |
| 95 | + stdx::sized8{(sizeof(id) + ... + sizeof(pack_as_t<Ts>))} |
| 96 | + .in<std::uint32_t>(); |
74 | 97 | using storage_t =
|
75 |
| - std::array<std::uint32_t, header_size + payload_len>; |
76 |
| - return catalog_builder<storage_t>{}.template build<Level>( |
77 |
| - id, m, msg_data...); |
| 98 | + std::array<std::uint32_t, header_size + payload_size>; |
| 99 | + return catalog_builder<storage_t>{}.template build<Level>(id, m, |
| 100 | + args...); |
78 | 101 | } else {
|
79 | 102 | constexpr auto header_size =
|
80 | 103 | defn::catalog_msg_t::size<std::uint8_t>::value;
|
81 |
| - constexpr auto payload_len = (sizeof(id) + ... + sizeof(Ts)); |
| 104 | + constexpr auto payload_size = (sizeof(id) + ... + sizeof(Ts)); |
82 | 105 | using storage_t =
|
83 |
| - std::array<std::uint8_t, header_size + payload_len>; |
84 |
| - return catalog_builder<storage_t>{}.template build<Level>( |
85 |
| - id, m, msg_data...); |
| 106 | + std::array<std::uint8_t, header_size + payload_size>; |
| 107 | + return catalog_builder<storage_t>{}.template build<Level>(id, m, |
| 108 | + args...); |
86 | 109 | }
|
87 | 110 | }
|
88 | 111 | };
|
89 | 112 |
|
90 | 113 | struct default_builder {
|
91 |
| - template <auto Level, std::same_as<std::uint32_t>... Ts> |
92 |
| - static auto build(string_id id, module_id m, Ts... msg_data) { |
| 114 | + template <auto Level, packable... Ts> |
| 115 | + static auto build(string_id id, module_id m, Ts... args) { |
93 | 116 | if constexpr (sizeof...(Ts) == 0u) {
|
94 |
| - return builder<defn::short32_msg_t>{}.template build<Level>( |
95 |
| - id, m, msg_data...); |
| 117 | + return builder<defn::short32_msg_t>{}.template build<Level>(id, m); |
96 | 118 | } else {
|
97 | 119 | return builder<defn::catalog_msg_t>{}.template build<Level>(
|
98 |
| - id, m, msg_data...); |
| 120 | + id, m, args...); |
99 | 121 | }
|
100 | 122 | }
|
101 | 123 | };
|
|
0 commit comments