Skip to content

Commit

Permalink
fix bug of overflow on full value bitwidth fields
Browse files Browse the repository at this point in the history
  • Loading branch information
Artur Bać committed Oct 15, 2022
1 parent b239081 commit 81ed8a1
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 3 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.20 FATAL_ERROR )

project(small_vectors
VERSION 1.0.9
VERSION 1.0.10
LANGUAGES CXX
HOMEPAGE_URL "https://github.com/arturbac/small_vectors"
)
Expand Down
22 changes: 20 additions & 2 deletions include/utils/meta_packed_struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,24 @@ namespace utils
return bit_width<next_member_t>() + my_bit_width;
}

/// \brief compile time bitmsk calculating
template <std::unsigned_integral T, uint32_t N>
struct bitmask_m {
static T constexpr value = bitmask_m < T, ( N - 1u ) >::value | T( T(1u) << ( N - 1 ) );
};

template <std::unsigned_integral T>
struct bitmask_m<T, 0u> {
static T constexpr value = T( 0u );
};
}

/// \brief compile time bitmsk calculating
template <std::unsigned_integral T, uint32_t number_of_bits>
constexpr T bitmask_v = detail::bitmask_m<T,number_of_bits>::value;

namespace detail
{
template<std::unsigned_integral pack_type, typename sub_member_type, typename meta_packed_struct>
constexpr auto pack_value(unsigned offset, meta_packed_struct const & ms )
-> pack_type
Expand All @@ -133,9 +151,9 @@ namespace utils
//cast meta to exactly my self inherited type
member_type const & self = static_cast<member_type const &>(ms);

unsigned bit_width = member_type::bit_width();
constexpr unsigned bit_width = member_type::bit_width();
pack_type value { static_cast<pack_type>(self.value) };
pack_type mask { static_cast<pack_type>((pack_type(1u)<<bit_width)-1u) };
pack_type mask { bitmask_v<pack_type,bit_width> };
if(std::is_constant_evaluated() )
{ if((mask & value) != value) throw "value outisde declared bit_width"; }
else
Expand Down
117 changes: 117 additions & 0 deletions unit_tests/meta_packed_struct_ut.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,54 @@ using bool_bitfiled_struct =

int main()
{

metatests::test_result result;
"test_bitmask"_test = [&result]
{
auto fn_test = []()
{
metatests::test_result tr;
{
tr |=constexpr_test(utils::bitmask_v<uint8_t,0> == 0x0u);
tr |=constexpr_test(utils::bitmask_v<uint8_t,8> == 0xFFu);
tr |=constexpr_test(utils::bitmask_v<uint8_t,7> == 0x7Fu);
tr |=constexpr_test(utils::bitmask_v<uint8_t,1> == 0x1u);

tr |=constexpr_test(utils::bitmask_v<uint16_t,7> == 0x7Fu);
tr |=constexpr_test(utils::bitmask_v<uint16_t,1> == 0x1u);
tr |=constexpr_test(utils::bitmask_v<uint16_t,8> == 0xFFu);
tr |=constexpr_test(utils::bitmask_v<uint16_t,13> == (1u<<13)-1);
tr |=constexpr_test(utils::bitmask_v<uint16_t,9> == (1u<<9)-1);
tr |=constexpr_test(utils::bitmask_v<uint16_t,16> == 0xFFFFu);

tr |=constexpr_test(utils::bitmask_v<uint32_t,8> == 0xFFu);
tr |=constexpr_test(utils::bitmask_v<uint32_t,7> == 0x7Fu);
tr |=constexpr_test(utils::bitmask_v<uint32_t,1> == 0x1u);
tr |=constexpr_test(utils::bitmask_v<uint32_t,28> == (1u<<28)-1);
tr |=constexpr_test(utils::bitmask_v<uint32_t,23> == (1u<<23)-1);
tr |=constexpr_test(utils::bitmask_v<uint32_t,29> == (1u<<29)-1);
tr |=constexpr_test(utils::bitmask_v<uint32_t,32> == 0xFFFFFFFFu);

tr |=constexpr_test(utils::bitmask_v<uint64_t,0> == 0x0u);
tr |=constexpr_test(utils::bitmask_v<uint64_t,8> == 0xFFu);
tr |=constexpr_test(utils::bitmask_v<uint64_t,7> == 0x7Fu);
tr |=constexpr_test(utils::bitmask_v<uint64_t,1> == 0x1u);
tr |=constexpr_test(utils::bitmask_v<uint64_t,28> == (1u<<28)-1);
tr |=constexpr_test(utils::bitmask_v<uint64_t,23> == (1u<<23)-1);
tr |=constexpr_test(utils::bitmask_v<uint64_t,29> == (1u<<29)-1);
tr |=constexpr_test(utils::bitmask_v<uint64_t,32> == 0xFFFFFFFFu);
tr |=constexpr_test(utils::bitmask_v<uint64_t,58> == (1LLu<<58)-1);
tr |=constexpr_test(utils::bitmask_v<uint64_t,53> == (1LLu<<53)-1);
tr |=constexpr_test(utils::bitmask_v<uint64_t,59> == (1LLu<<59)-1);
tr |=constexpr_test(utils::bitmask_v<uint64_t,64> == 0xFFFFFFFFFFFFFFFFLLu);
}

return tr;
};
result |= metatests::run_constexpr_test(fn_test);
result |= metatests::run_consteval_test(fn_test);
};

"test_metabitstruct_bool"_test = [&result]
{
auto fn_test = []()
Expand Down Expand Up @@ -233,8 +280,78 @@ using mixed_bitfiled_struct =
result |= metatests::run_constexpr_test(fn_test);
result |= metatests::run_consteval_test(fn_test);
};

using mixed_bitfiled_struct3 =
meta_packed_struct<
member<uint8_t,mbs_fields::field_1,4>,
member<bool,mbs_fields::field_2,1>,
member<uint64_t ,mbs_fields::field_3,56>,
member<example_enum_value, mbs_fields::field_4,3>
>;
"test_metabitstruct_mixed3"_test = [&result]
{
auto fn_test = []()
{
metatests::test_result tr;
using enum mbs_fields;
constexpr auto fcount = filed_count<mixed_bitfiled_struct3>();
tr |= constexpr_test(fcount == 4);
constexpr auto s_bit_width = bit_width<mixed_bitfiled_struct3>();
tr |= constexpr_test(s_bit_width == 64);
{
mixed_bitfiled_struct3 mbs;
get<field_1>(mbs) = 0b1111;
tr |= constexpr_test(get<field_1>(mbs) == 0b1111 );
tr |= constexpr_test(get<field_2>(mbs) == false );
tr |= constexpr_test(get<field_3>(mbs) == 0 );
tr |= constexpr_test(get<field_4>(mbs) == example_enum_value{} );

auto packed_value = pack_value<uint64_t>(mbs);
tr |= constexpr_test(packed_value == 0b1111 );
}
{
mixed_bitfiled_struct3 mbs;
get<field_2>(mbs) = true;
tr |= constexpr_test(get<field_1>(mbs) == 0 );
tr |= constexpr_test(get<field_2>(mbs) == true );
tr |= constexpr_test(get<field_3>(mbs) == 0 );
tr |= constexpr_test(get<field_4>(mbs) == example_enum_value{} );

auto packed_value = pack_value<uint64_t>(mbs);
tr |= constexpr_test(packed_value == 0b10000 );
}
{
mixed_bitfiled_struct3 mbs;
get<field_3>(mbs) = (0x1llu<<56)-1;
tr |= constexpr_test(get<field_1>(mbs) == 0 );
tr |= constexpr_test(get<field_2>(mbs) == false );
tr |= constexpr_test(get<field_3>(mbs) == (0x1llu<<56)-1 );
tr |= constexpr_test(get<field_4>(mbs) == example_enum_value{} );

auto packed_value = pack_value<uint64_t>(mbs);
tr |= constexpr_test(packed_value == 0b00'11111111111111111111111111111111111111111111111111111111'0'0000 );
}
{
using enum example_enum_value;
mixed_bitfiled_struct3 mbs;
get<field_2>(mbs) = true;
get<field_3>(mbs) = 0b01111111111111111111111111111111111111111111111111111110;
get<field_4>(mbs) = value2;
tr |= constexpr_test(get<field_1>(mbs) == 0 );
tr |= constexpr_test(get<field_2>(mbs) == true );
tr |= constexpr_test(get<field_3>(mbs) == 0b01111111111111111111111111111111111111111111111111111110 );
tr |= constexpr_test(get<field_4>(mbs) == value2 );

auto packed_value = pack_value<uint64_t>(mbs);
tr |= constexpr_test(packed_value == 0b10'01111111111111111111111111111111111111111111111111111110'1'0000 );

}
return tr;
};
result |= metatests::run_constexpr_test(fn_test);
result |= metatests::run_consteval_test(fn_test);
};

"test_metabitstruct_mixed_constrcution"_test = [&result]
{
auto fn_test = []()
Expand Down

0 comments on commit 81ed8a1

Please sign in to comment.