mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2024-11-26 13:25:54 +00:00
👷 Smarter Flags<N> templates (#27309)
This commit is contained in:
parent
bcbdac6f6c
commit
2d32f7c377
@ -64,7 +64,7 @@
|
||||
|
||||
// Macros for bit masks
|
||||
#undef _BV
|
||||
#define _BV(n) (1<<(n))
|
||||
#define _BV(b) (1 << (b))
|
||||
#define TEST(n,b) (!!((n)&_BV(b)))
|
||||
#define SET_BIT_TO(N,B,TF) do{ if (TF) SBI(N,B); else CBI(N,B); }while(0)
|
||||
#ifndef SBI
|
||||
|
@ -159,36 +159,90 @@ template <class L, class R> struct IF<true, L, R> { 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<size_t N, bool UseArray = (N > 64)>
|
||||
struct Flags;
|
||||
|
||||
// Flag bits for <= 64 states
|
||||
template<size_t N>
|
||||
struct Flags {
|
||||
struct Flags<N, false> {
|
||||
typedef bits_t(N) flagbits_t;
|
||||
typedef struct { bool b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1; } N8;
|
||||
typedef struct { bool b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1, b8:1, b9:1, b10:1, b11:1, b12:1, b13:1, b14:1, b15:1; } N16;
|
||||
typedef struct { bool b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1, b8:1, b9:1, b10:1, b11:1, b12:1, b13:1, b14:1, b15:1,
|
||||
b16:1, b17:1, b18:1, b19:1, b20:1, b21:1, b22:1, b23:1, b24:1, b25:1, b26:1, b27:1, b28:1, b29:1, b30:1, b31:1; } N32;
|
||||
union {
|
||||
flagbits_t b;
|
||||
typename IF<(N>16), N32, typename IF<(N>8), N16, N8>::type>::type flag;
|
||||
flagbits_t b;
|
||||
|
||||
class BitProxy {
|
||||
public:
|
||||
BitProxy(flagbits_t& data, int bit) : data_(data), bit_(bit) {}
|
||||
|
||||
BitProxy& operator=(const bool value) {
|
||||
if (value)
|
||||
data_ |= (flagbits_t(1) << bit_);
|
||||
else
|
||||
data_ &= ~(flagbits_t(1) << bit_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const { return bool(data_ & (flagbits_t(1) << 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 |= (flagbits_t)_BV(n); }
|
||||
FI void clear(const int n) { b &= ~(flagbits_t)_BV(n); }
|
||||
FI bool test(const int n) const { return TEST(b, n); }
|
||||
FI bool operator[](const int n) { return test(n); }
|
||||
FI void set(const int n) { b |= (flagbits_t(1) << n); }
|
||||
FI void clear(const int n) { b &= ~(flagbits_t(1) << n); }
|
||||
FI bool test(const int n) const { return bool(b & (flagbits_t(1) << 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; }
|
||||
FI operator bool() const { return b != 0; }
|
||||
};
|
||||
|
||||
// Flag bits for more than 64 states
|
||||
template<size_t N>
|
||||
struct Flags<N, true> {
|
||||
uint8_t bitmask[(N+7)>>3];
|
||||
// Proxy class for handling bit assignment
|
||||
class BitProxy {
|
||||
public:
|
||||
BitProxy(uint8_t data[], int n) : data_(data[n >> 3]), bit_(n & 7) {}
|
||||
|
||||
// Assignment operator
|
||||
BitProxy& operator=(const bool value) {
|
||||
if (value)
|
||||
data_ |= _BV(bit_);
|
||||
else
|
||||
data_ &= ~_BV(bit_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Conversion operator to bool
|
||||
operator bool() const { return TEST(data_, bit_); }
|
||||
|
||||
private:
|
||||
uint8_t& data_;
|
||||
uint8_t bit_;
|
||||
};
|
||||
|
||||
FI void reset() { for (uint8_t b = 0; b < sizeof(bitmask); ++b) bitmask[b] = 0; }
|
||||
FI void set(const int n, const bool onoff) { onoff ? set(n) : clear(n); }
|
||||
FI void set(const int n) { bitmask[n >> 3] |= _BV(n & 7); }
|
||||
FI void clear(const int n) { bitmask[n >> 3] &= ~_BV(n & 7); }
|
||||
FI bool test(const int n) const { return TEST(bitmask[n >> 3], n & 7); }
|
||||
FI BitProxy operator[](const int n) { return BitProxy(bitmask, n); }
|
||||
FI bool operator[](const int n) const { return test(n); }
|
||||
FI int size() const { return sizeof(bitmask); }
|
||||
FI operator bool() const { for (uint8_t b : bitmask) if (b) return true; return false; }
|
||||
};
|
||||
|
||||
// Specialization for a single bool flag
|
||||
template<>
|
||||
struct Flags<1> {
|
||||
struct Flags<1, false> {
|
||||
bool b;
|
||||
FI void reset() { b = false; }
|
||||
FI void set(const int n, const bool onoff) { onoff ? set(n) : clear(n); }
|
||||
@ -218,7 +272,7 @@ typedef struct {
|
||||
FI bool operator[](const int n) { return flags[n]; }
|
||||
FI bool operator[](const int n) const { return flags[n]; }
|
||||
FI int size() const { return sizeof(flags); }
|
||||
FI operator bool() const { return flags; }
|
||||
FI operator bool() const { return (bool)flags; }
|
||||
} AxisFlags;
|
||||
|
||||
//
|
||||
|
@ -532,6 +532,59 @@ 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(8, flags.size());
|
||||
}
|
||||
|
||||
MARLIN_TEST(types, Flags_302) {
|
||||
Flags<302> flags;
|
||||
|
||||
flags.reset();
|
||||
TEST_ASSERT_EQUAL(false, (bool)flags);
|
||||
|
||||
flags.set(0, true);
|
||||
flags.set(301, true);
|
||||
|
||||
TEST_ASSERT_EQUAL(true, (bool)flags);
|
||||
|
||||
TEST_ASSERT_EQUAL(true, flags.test(0));
|
||||
TEST_ASSERT_EQUAL(true, flags.test(301));
|
||||
TEST_ASSERT_EQUAL(false, flags.test(1));
|
||||
TEST_ASSERT_EQUAL(false, flags.test(300));
|
||||
|
||||
TEST_ASSERT_EQUAL(true, flags[0]);
|
||||
TEST_ASSERT_EQUAL(true, flags[301]);
|
||||
TEST_ASSERT_EQUAL(false, flags[1]);
|
||||
TEST_ASSERT_EQUAL(false, flags[300]);
|
||||
|
||||
TEST_ASSERT_EQUAL(38, flags.size());
|
||||
}
|
||||
|
||||
MARLIN_TEST(types, AxisFlags_const_as_bools) {
|
||||
const AxisFlags axis_flags_const_false = {0};
|
||||
TEST_ASSERT_FALSE(axis_flags_const_false);
|
||||
|
Loading…
Reference in New Issue
Block a user