Skip to content

Commit 84bde7b

Browse files
committed
✨ Add uninitialized state for fields
Problem: - Sometimes it is useful to use fields that overlap: for instance to be able to inspect individual bits _and_ have an overlapping field that represents the set of bits as a whole. In these cases it is useful at construction time to leave such an overlapping field uninitialized so that we don't have a scenario where one initialization overwrites another. Solution: - Allow a field to be marked as `uninitialized` so that on construction it won't potentially clobber other fields. Note: - The difference between `without_default` and `uninitialized` is that a field marked `without_default` must still be given a value at construction time.
1 parent f701a01 commit 84bde7b

File tree

3 files changed

+26
-6
lines changed

3 files changed

+26
-6
lines changed

include/msg/field.hpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,28 +362,30 @@ template <at... Ats> constexpr inline auto field_size = (0u + ... + Ats.size());
362362

363363
template <typename T, T V = T{}> struct with_default {
364364
constexpr static auto default_value = V;
365-
template <typename F> using default_matcher_t = msg::equal_to_t<F, V>;
366365
using is_mutable_t = void;
367366
template <T X> constexpr static auto is_compatible_value = true;
368367
};
369368

370369
template <typename T, T V = T{}> struct with_const_default {
371370
constexpr static auto default_value = V;
372-
template <typename F> using default_matcher_t = msg::equal_to_t<F, V>;
373371
template <T X> constexpr static auto is_compatible_value = X == V;
374372
};
375373

376374
struct without_default {
377-
template <typename F> using default_matcher_t = match::never_t;
378375
using is_mutable_t = void;
379376
template <auto X> constexpr static auto is_compatible_value = true;
380377
};
381378

379+
struct uninitialized {
380+
template <auto X> constexpr static auto is_compatible_value = true;
381+
};
382+
382383
template <typename T>
383384
concept has_default_value = requires { T::default_value; };
384385

385386
template <typename T>
386-
using has_default_value_t = std::bool_constant<has_default_value<T>>;
387+
using initializable_t = std::bool_constant<has_default_value<T> or
388+
std::is_base_of_v<uninitialized, T>>;
387389

388390
template <typename T>
389391
concept is_mutable_value = requires { typename T::is_mutable_t; };
@@ -489,6 +491,8 @@ class field_t : public field_spec_t<Name, T, detail::field_size<Ats...>>,
489491
using without_default =
490492
field_t<Name, T, detail::without_default, M, Ats...>;
491493

494+
using uninitialized = field_t<Name, T, detail::uninitialized, M, Ats...>;
495+
492496
// ======================================================================
493497
// matcher values
494498
template <typename NewMatcher>

include/msg/message.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ struct message {
497497
constexpr owner_t() {
498498
using uninit_fields =
499499
boost::mp11::mp_remove_if<boost::mp11::mp_list<Fields...>,
500-
has_default_value_t>;
500+
initializable_t>;
501501
static_assert(boost::mp11::mp_empty<uninit_fields>::value,
502502
"All fields must be initialized or defaulted");
503503
this->set(Fields{}...);
@@ -507,7 +507,7 @@ struct message {
507507
using defaulted_fields = boost::mp11::mp_transform<
508508
name_for,
509509
boost::mp11::mp_copy_if<boost::mp11::mp_list<Fields...>,
510-
has_default_value_t>>;
510+
initializable_t>>;
511511
using initialized_fields =
512512
boost::mp11::mp_transform<name_for,
513513
boost::mp11::mp_list<Vs...>>;

test/msg/message.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,3 +824,19 @@ TEST_CASE("write indexing operator on message", "[message]") {
824824
CHECK((0xba11 == msg["f1"_field]));
825825
}
826826
#endif
827+
828+
namespace {
829+
using bit_field1 =
830+
field<"f1",
831+
std::uint32_t>::located<at{0_dw, 0_msb, 0_lsb}>::with_required<1>;
832+
using all_fields =
833+
field<"all", std::uint32_t>::located<at{0_dw, 31_msb, 0_lsb}>;
834+
835+
using overlap_msg_defn = message<"msg", bit_field1, all_fields::uninitialized>;
836+
} // namespace
837+
838+
TEST_CASE("message with uninitialized field", "[message]") {
839+
owning<overlap_msg_defn> msg{};
840+
auto data = msg.data();
841+
CHECK(data[0] == 1);
842+
}

0 commit comments

Comments
 (0)