diff --git a/include/msg/field.hpp b/include/msg/field.hpp index 1b287715..a6bc7bf1 100644 --- a/include/msg/field.hpp +++ b/include/msg/field.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include namespace msg { template @@ -331,6 +333,9 @@ struct at { [[nodiscard]] constexpr auto lsb() const -> std::underlying_type_t { return stdx::to_underlying(lsb_) % 32u; } + [[nodiscard]] constexpr auto msb() const -> std::underlying_type_t { + return stdx::to_underlying(msb_); + } [[nodiscard]] constexpr auto size() const -> std::underlying_type_t { return stdx::to_underlying(msb_) - stdx::to_underlying(lsb_) + 1; } @@ -424,6 +429,13 @@ class field_t : public field_spec_t>, return locator_t::template extract(std::forward(r)); } + template + [[nodiscard]] constexpr static auto extract(U const &u) -> value_type { + static_assert(stdx::bit_size() > std::max({0u, Ats.msb()...}), + "Field location is outside the range of argument!"); + return extract(stdx::span{std::addressof(u), 1}); + } + template constexpr static void insert(R &&r, value_type const &value) { static_assert(is_mutable_value, @@ -431,6 +443,13 @@ class field_t : public field_spec_t>, locator_t::template insert(std::forward(r), value); } + template + constexpr static void insert(U &u, value_type const &value) { + static_assert(stdx::bit_size() > std::max({0u, Ats.msb()...}), + "Field location is outside the range of argument!"); + insert(stdx::span{std::addressof(u), 1}, value); + } + template constexpr static void insert_default(R &&r) { if constexpr (has_default_value) { locator_t::template insert(std::forward(r), diff --git a/test/msg/fail/CMakeLists.txt b/test/msg/fail/CMakeLists.txt index c2c5c650..5c44f143 100644 --- a/test/msg/fail/CMakeLists.txt +++ b/test/msg/fail/CMakeLists.txt @@ -1,4 +1,5 @@ add_compile_fail_test(callback_bad_field_name.cpp LIBRARIES warnings cib_msg) +add_compile_fail_test(field_insert_space.cpp LIBRARIES warnings cib_msg) add_compile_fail_test(field_location.cpp LIBRARIES warnings cib_msg) add_compile_fail_test(field_size.cpp LIBRARIES warnings cib_msg) add_compile_fail_test(impossible_match_callback.cpp LIBRARIES warnings cib_msg) diff --git a/test/msg/fail/field_insert_space.cpp b/test/msg/fail/field_insert_space.cpp new file mode 100644 index 00000000..ea99fca0 --- /dev/null +++ b/test/msg/fail/field_insert_space.cpp @@ -0,0 +1,13 @@ +#include + +#include + +// EXPECT: Field location is outside the range of argument + +using namespace msg; +using F = field<"", std::uint8_t>::located; + +auto main() -> int { + std::uint32_t data{}; + F::insert(data, 1u); +} diff --git a/test/msg/field_extract.cpp b/test/msg/field_extract.cpp index eedcce7f..8d33be2e 100644 --- a/test/msg/field_extract.cpp +++ b/test/msg/field_extract.cpp @@ -16,6 +16,12 @@ TEST_CASE("single bit", "[field extract]") { CHECK(0b1u == F::extract(data)); } +TEST_CASE("from integral type", "[field extract]") { + using F = field<"", std::uint32_t>::located; + std::uint32_t data{0b010}; + CHECK(0b1u == F::extract(data)); +} + TEST_CASE("within one storage element", "[field extract]") { using F = field<"", std::uint32_t>::located; std::array data{0b11'1010'1010'1110'0000}; diff --git a/test/msg/field_insert.cpp b/test/msg/field_insert.cpp index ec49ab20..f455dc00 100644 --- a/test/msg/field_insert.cpp +++ b/test/msg/field_insert.cpp @@ -16,6 +16,13 @@ TEST_CASE("single bit", "[field insert]") { CHECK(0b010u == data[0]); } +TEST_CASE("into integral type", "[field insert]") { + using F = field<"", std::uint32_t>::located; + std::uint32_t data{}; + F::insert(data, 1u); + CHECK(0b010u == data); +} + TEST_CASE("within one storage element", "[field insert]") { using F = field<"", std::uint32_t>::located; std::array data{0b10'0000'0000'0001'0000};