Skip to content

Commit dbf7b1e

Browse files
authored
Merge pull request #739 from elbeno/integral-field-extract
✨ Allow field insert/extract on integral types
2 parents 661a934 + 063e23c commit dbf7b1e

File tree

5 files changed

+46
-0
lines changed

5 files changed

+46
-0
lines changed

include/msg/field.hpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <stdx/ct_string.hpp>
1111
#include <stdx/iterator.hpp>
1212
#include <stdx/ranges.hpp>
13+
#include <stdx/span.hpp>
1314
#include <stdx/type_traits.hpp>
1415

1516
#include <algorithm>
@@ -20,6 +21,7 @@
2021
#include <limits>
2122
#include <span>
2223
#include <type_traits>
24+
#include <utility>
2325

2426
namespace msg {
2527
template <typename T>
@@ -331,6 +333,9 @@ struct at {
331333
[[nodiscard]] constexpr auto lsb() const -> std::underlying_type_t<lsb_t> {
332334
return stdx::to_underlying(lsb_) % 32u;
333335
}
336+
[[nodiscard]] constexpr auto msb() const -> std::underlying_type_t<msb_t> {
337+
return stdx::to_underlying(msb_);
338+
}
334339
[[nodiscard]] constexpr auto size() const -> std::underlying_type_t<lsb_t> {
335340
return stdx::to_underlying(msb_) - stdx::to_underlying(lsb_) + 1;
336341
}
@@ -424,13 +429,27 @@ class field_t : public field_spec_t<Name, T, detail::field_size<Ats...>>,
424429
return locator_t::template extract<spec_t>(std::forward<R>(r));
425430
}
426431

432+
template <std::unsigned_integral U>
433+
[[nodiscard]] constexpr static auto extract(U const &u) -> value_type {
434+
static_assert(stdx::bit_size<U>() > std::max({0u, Ats.msb()...}),
435+
"Field location is outside the range of argument!");
436+
return extract(stdx::span{std::addressof(u), 1});
437+
}
438+
427439
template <stdx::range R>
428440
constexpr static void insert(R &&r, value_type const &value) {
429441
static_assert(is_mutable_value<field_t>,
430442
"Can't change a field with a required value!");
431443
locator_t::template insert<spec_t>(std::forward<R>(r), value);
432444
}
433445

446+
template <std::unsigned_integral U>
447+
constexpr static void insert(U &u, value_type const &value) {
448+
static_assert(stdx::bit_size<U>() > std::max({0u, Ats.msb()...}),
449+
"Field location is outside the range of argument!");
450+
insert(stdx::span{std::addressof(u), 1}, value);
451+
}
452+
434453
template <stdx::range R> constexpr static void insert_default(R &&r) {
435454
if constexpr (has_default_value<Default>) {
436455
locator_t::template insert<spec_t>(std::forward<R>(r),

test/msg/fail/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_compile_fail_test(callback_bad_field_name.cpp LIBRARIES warnings cib_msg)
2+
add_compile_fail_test(field_insert_space.cpp LIBRARIES warnings cib_msg)
23
add_compile_fail_test(field_location.cpp LIBRARIES warnings cib_msg)
34
add_compile_fail_test(field_size.cpp LIBRARIES warnings cib_msg)
45
add_compile_fail_test(impossible_match_callback.cpp LIBRARIES warnings cib_msg)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <msg/field.hpp>
2+
3+
#include <cstdint>
4+
5+
// EXPECT: Field location is outside the range of argument
6+
7+
using namespace msg;
8+
using F = field<"", std::uint8_t>::located<at{32_msb, 31_lsb}>;
9+
10+
auto main() -> int {
11+
std::uint32_t data{};
12+
F::insert(data, 1u);
13+
}

test/msg/field_extract.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ TEST_CASE("single bit", "[field extract]") {
1616
CHECK(0b1u == F::extract(data));
1717
}
1818

19+
TEST_CASE("from integral type", "[field extract]") {
20+
using F = field<"", std::uint32_t>::located<at{0_dw, 1_msb, 1_lsb}>;
21+
std::uint32_t data{0b010};
22+
CHECK(0b1u == F::extract(data));
23+
}
24+
1925
TEST_CASE("within one storage element", "[field extract]") {
2026
using F = field<"", std::uint32_t>::located<at{0_dw, 16_msb, 5_lsb}>;
2127
std::array<std::uint32_t, 1> data{0b11'1010'1010'1110'0000};

test/msg/field_insert.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ TEST_CASE("single bit", "[field insert]") {
1616
CHECK(0b010u == data[0]);
1717
}
1818

19+
TEST_CASE("into integral type", "[field insert]") {
20+
using F = field<"", std::uint32_t>::located<at{0_dw, 1_msb, 1_lsb}>;
21+
std::uint32_t data{};
22+
F::insert(data, 1u);
23+
CHECK(0b010u == data);
24+
}
25+
1926
TEST_CASE("within one storage element", "[field insert]") {
2027
using F = field<"", std::uint32_t>::located<at{0_dw, 16_msb, 5_lsb}>;
2128
std::array<std::uint32_t, 1> data{0b10'0000'0000'0001'0000};

0 commit comments

Comments
 (0)