Skip to content

Commit 417ee86

Browse files
authored
Merge pull request #777 from elbeno/msg-indexing
🚸 Add `operator[]` to messages
2 parents 3622553 + 52fa254 commit 417ee86

File tree

5 files changed

+85
-4
lines changed

5 files changed

+85
-4
lines changed

include/msg/message.hpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,10 @@ template <stdx::ct_string Name, typename... Fields> class msg_access {
198198
using FieldsTuple =
199199
decltype(stdx::make_indexed_tuple<name_for>(Fields{}...));
200200

201-
template <typename Field, stdx::range R> constexpr static auto check() {
201+
template <typename N, stdx::range R> constexpr static auto check() {
202+
static_assert((std::is_same_v<N, name_for<Fields>> or ...),
203+
"Field does not belong to this message!");
204+
using Field = field_t<N>;
202205
constexpr auto belongs = (std::is_same_v<typename Field::field_id,
203206
typename Fields::field_id> or
204207
...);
@@ -209,20 +212,20 @@ template <stdx::ct_string Name, typename... Fields> class msg_access {
209212

210213
template <stdx::range R, some_field_value V>
211214
constexpr static auto set1(R &&r, V v) -> void {
215+
check<name_for<V>, std::remove_cvref_t<R>>();
212216
using Field = field_t<name_for<V>>;
213-
check<Field, std::remove_cvref_t<R>>();
214217
Field::insert(std::forward<R>(r),
215218
static_cast<typename Field::value_type>(v.value));
216219
}
217220

218221
template <typename N, stdx::range R>
219222
constexpr static auto set_default(R &&r) -> void {
220-
check<field_t<N>, std::remove_cvref_t<R>>();
223+
check<N, std::remove_cvref_t<R>>();
221224
field_t<N>::insert_default(std::forward<R>(r));
222225
}
223226

224227
template <typename N, stdx::range R> constexpr static auto get(R &&r) {
225-
check<field_t<N>, std::remove_cvref_t<R>>();
228+
check<N, std::remove_cvref_t<R>>();
226229
return field_t<N>::extract(std::forward<R>(r));
227230
}
228231

@@ -341,11 +344,36 @@ template <stdx::ct_string Name, typename Access, typename T> struct msg_base {
341344
[[nodiscard]] constexpr auto get(auto f) const {
342345
return Access::get(as_derived().data(), f);
343346
}
347+
344348
constexpr auto set(auto... fs) -> void {
345349
Access::set(as_derived().data(), fs...);
346350
}
347351
constexpr auto set() -> void {}
348352

353+
template <stdx::ct_string N> struct proxy {
354+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
355+
msg_base &b;
356+
357+
// NOLINTNEXTLINE(misc-unconventional-assign-operator)
358+
constexpr auto operator=(auto val) const && -> void {
359+
b.set(field_name<N>{} = val);
360+
}
361+
362+
using V = decltype(b.get(std::declval<field_name<N>>()));
363+
364+
// NOLINTNEXTLINE(google-explicit-constructor)
365+
constexpr operator V() const { return b.get(field_name<N>{}); }
366+
};
367+
368+
template <stdx::ct_string N>
369+
[[nodiscard]] constexpr auto operator[](field_name<N> f) const {
370+
return get(f);
371+
}
372+
template <stdx::ct_string N>
373+
[[nodiscard]] constexpr auto operator[](field_name<N>) LIFETIMEBOUND {
374+
return proxy<N>{*this};
375+
}
376+
349377
[[nodiscard]] constexpr auto describe() const {
350378
return Access::describe(as_derived().data());
351379
}

test/msg/fail/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ add_compile_fail_test(message_cmp_view.cpp LIBRARIES warnings cib_msg)
1313
add_compile_fail_test(message_const_field_write.cpp LIBRARIES warnings cib_msg)
1414
add_compile_fail_test(message_dangling_view.cpp LIBRARIES warnings cib_msg)
1515
add_compile_fail_test(message_dup_fieldnames.cpp LIBRARIES warnings cib_msg)
16+
add_compile_fail_test(message_get_nonexistent_field.cpp LIBRARIES warnings
17+
cib_msg)
1618
add_compile_fail_test(message_incompatible_matcher.cpp LIBRARIES warnings
1719
cib_msg)
20+
add_compile_fail_test(message_set_nonexistent_field.cpp LIBRARIES warnings
21+
cib_msg)
1822
add_compile_fail_test(message_uninitialized_field.cpp LIBRARIES warnings
1923
cib_msg)
2024
add_compile_fail_test(view_upsize.cpp LIBRARIES warnings cib_msg)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <msg/field.hpp>
2+
#include <msg/message.hpp>
3+
4+
// EXPECT: Field does not belong to this message
5+
namespace {
6+
using namespace msg;
7+
8+
using test_field1 =
9+
field<"test_field", std::uint32_t>::located<at{0_dw, 31_msb, 24_lsb}>;
10+
11+
using msg_defn = message<"test_msg", test_field1>;
12+
} // namespace
13+
14+
auto main() -> int {
15+
owning<msg_defn> m{};
16+
[[maybe_unused]] auto f = m.get("no"_field);
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <msg/field.hpp>
2+
#include <msg/message.hpp>
3+
4+
// EXPECT: Field does not belong to this message
5+
namespace {
6+
using namespace msg;
7+
8+
using test_field1 =
9+
field<"test_field", std::uint32_t>::located<at{0_dw, 31_msb, 24_lsb}>;
10+
11+
using msg_defn = message<"test_msg", test_field1>;
12+
} // namespace
13+
14+
auto main() -> int {
15+
owning<msg_defn> m{};
16+
m.set("no"_field = 1);
17+
}

test/msg/message.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,3 +792,18 @@ TEST_CASE("pack appends environments", "[message]") {
792792
using defn = pack<"defn", std::uint8_t, m1, m2>;
793793
STATIC_REQUIRE(custom(defn::env_t{}) == 18);
794794
}
795+
796+
TEST_CASE("read indexing operator on message", "[message]") {
797+
test_msg const msg{};
798+
CHECK(0x80 == msg["id"_field]);
799+
}
800+
801+
// This test causes clang-14 with libc++ to crash...
802+
#if not __clang__ or __clang_major__ > 14
803+
TEST_CASE("write indexing operator on message", "[message]") {
804+
test_msg msg{};
805+
CHECK((0 == msg["f1"_field]));
806+
msg["f1"_field] = 0xba11;
807+
CHECK((0xba11 == msg["f1"_field]));
808+
}
809+
#endif

0 commit comments

Comments
 (0)