Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

👷 Smarter Flags<N> templates #27309

Merged
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
2 changes: 1 addition & 1 deletion Marlin/src/core/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
88 changes: 71 additions & 17 deletions Marlin/src/core/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand Down Expand Up @@ -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;

//
Expand Down
53 changes: 53 additions & 0 deletions Marlin/tests/core/test_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading