diff --git a/Marlin/src/core/types.h b/Marlin/src/core/types.h index 344c9b7523136..1e47da6cbc18b 100644 --- a/Marlin/src/core/types.h +++ b/Marlin/src/core/types.h @@ -159,13 +159,53 @@ template struct IF { typedef L type; }; #define FI FORCE_INLINE // Define types based on largest bit width stored value required -#define bits_t(W) typename IF<((W)> 16), uint32_t, typename IF<((W)> 8), uint16_t, uint8_t>::type>::type +#define bits_t(W) typename IF<((W)>32), uint64_t, typename IF<((W)>16), uint32_t, typename IF<((W)>8), uint16_t, uint8_t>::type>::type>::type #define uvalue_t(V) typename IF<((V)>65535), uint32_t, typename IF<((V)>255), uint16_t, uint8_t>::type>::type #define value_t(V) typename IF<((V)>32767), int32_t, typename IF<((V)>127), int16_t, int8_t>::type>::type -// General Flags for some number of states +// Define a template for a bit field of N bits, using the smallest type that can hold N bits +template 64)> +struct Flags; + +// Flag bits for <= 64 states +template +struct Flags { + typedef bits_t(N) flagbits_t; + flagbits_t b; + + class BitProxy { + public: + BitProxy(flagbits_t& data, int bit) : data_(data), bit_(bit) {} + + BitProxy& operator=(const bool value) { + if (value) + data_ |= _BV(bit_); + else + data_ &= ~_BV(bit_); + return *this; + } + + operator bool() const { return TEST(data_, bit_); } + + private: + flagbits_t& data_; + uint8_t bit_; + }; + + FI void reset() { b = 0; } + FI void set(const int n, const bool onoff) { onoff ? set(n) : clear(n); } + FI void set(const int n) { b |= _BV(n); } + FI void clear(const int n) { b &= ~_BV(n); } + FI bool test(const int n) const { return TEST(b, n); } + FI BitProxy operator[](const int n) { return BitProxy(b, n); } + FI bool operator[](const int n) const { return test(n); } + FI int size() const { return sizeof(b); } + FI operator bool() const { return b != 0; } +}; + +// Flag bits for more than 64 states template -struct Flags { +struct Flags { uint8_t bitmask[(N+7)>>3]; // Proxy class for handling bit assignment class BitProxy { diff --git a/Marlin/tests/core/test_types.cpp b/Marlin/tests/core/test_types.cpp index 865d35de158c9..e34f79c6b46ae 100644 --- a/Marlin/tests/core/test_types.cpp +++ b/Marlin/tests/core/test_types.cpp @@ -532,6 +532,35 @@ MARLIN_TEST(types, Flags_32) { TEST_ASSERT_EQUAL(4, flags.size()); } +MARLIN_TEST(types, Flags_64) { + Flags<64> flags; + + flags.reset(); + TEST_ASSERT_EQUAL(0, flags.b); + + flags.set(0, true); + flags.set(63, true); + TEST_ASSERT_EQUAL(9223372036854775809ULL, flags.b); + + flags.clear(0); + flags.clear(63); + TEST_ASSERT_EQUAL(0, flags.b); + + flags.set(0, true); + flags.set(63, true); + TEST_ASSERT_EQUAL(true, flags.test(0)); + TEST_ASSERT_EQUAL(true, flags.test(63)); + TEST_ASSERT_EQUAL(false, flags.test(1)); + TEST_ASSERT_EQUAL(false, flags.test(62)); + + TEST_ASSERT_EQUAL(true, flags[0]); + TEST_ASSERT_EQUAL(true, flags[63]); + TEST_ASSERT_EQUAL(false, flags[1]); + TEST_ASSERT_EQUAL(false, flags[62]); + + TEST_ASSERT_EQUAL(4, flags.size()); +} + MARLIN_TEST(types, AxisFlags_const_as_bools) { const AxisFlags axis_flags_const_false = {0}; TEST_ASSERT_FALSE(axis_flags_const_false);