Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions include/msg/field.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <stdx/ct_string.hpp>
#include <stdx/iterator.hpp>
#include <stdx/ranges.hpp>
#include <stdx/span.hpp>
#include <stdx/type_traits.hpp>

#include <algorithm>
Expand All @@ -20,6 +21,7 @@
#include <limits>
#include <span>
#include <type_traits>
#include <utility>

namespace msg {
template <typename T>
Expand Down Expand Up @@ -331,6 +333,9 @@ struct at {
[[nodiscard]] constexpr auto lsb() const -> std::underlying_type_t<lsb_t> {
return stdx::to_underlying(lsb_) % 32u;
}
[[nodiscard]] constexpr auto msb() const -> std::underlying_type_t<msb_t> {
return stdx::to_underlying(msb_);
}
[[nodiscard]] constexpr auto size() const -> std::underlying_type_t<lsb_t> {
return stdx::to_underlying(msb_) - stdx::to_underlying(lsb_) + 1;
}
Expand Down Expand Up @@ -424,13 +429,27 @@ class field_t : public field_spec_t<Name, T, detail::field_size<Ats...>>,
return locator_t::template extract<spec_t>(std::forward<R>(r));
}

template <std::unsigned_integral U>
[[nodiscard]] constexpr static auto extract(U const &u) -> value_type {
static_assert(stdx::bit_size<U>() > std::max({0u, Ats.msb()...}),
"Field location is outside the range of argument!");
return extract(stdx::span{std::addressof(u), 1});
}

template <stdx::range R>
constexpr static void insert(R &&r, value_type const &value) {
static_assert(is_mutable_value<field_t>,
"Can't change a field with a required value!");
locator_t::template insert<spec_t>(std::forward<R>(r), value);
}

template <std::unsigned_integral U>
constexpr static void insert(U &u, value_type const &value) {
static_assert(stdx::bit_size<U>() > std::max({0u, Ats.msb()...}),
"Field location is outside the range of argument!");
insert(stdx::span{std::addressof(u), 1}, value);
}

template <stdx::range R> constexpr static void insert_default(R &&r) {
if constexpr (has_default_value<Default>) {
locator_t::template insert<spec_t>(std::forward<R>(r),
Expand Down
1 change: 1 addition & 0 deletions test/msg/fail/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
13 changes: 13 additions & 0 deletions test/msg/fail/field_insert_space.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <msg/field.hpp>

#include <cstdint>

// EXPECT: Field location is outside the range of argument

using namespace msg;
using F = field<"", std::uint8_t>::located<at{32_msb, 31_lsb}>;

auto main() -> int {
std::uint32_t data{};
F::insert(data, 1u);
}
6 changes: 6 additions & 0 deletions test/msg/field_extract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<at{0_dw, 1_msb, 1_lsb}>;
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<at{0_dw, 16_msb, 5_lsb}>;
std::array<std::uint32_t, 1> data{0b11'1010'1010'1110'0000};
Expand Down
7 changes: 7 additions & 0 deletions test/msg/field_insert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<at{0_dw, 1_msb, 1_lsb}>;
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<at{0_dw, 16_msb, 5_lsb}>;
std::array<std::uint32_t, 1> data{0b10'0000'0000'0001'0000};
Expand Down
Loading