Last active
August 29, 2015 14:10
-
-
Save salkinium/766dbcea1a700a83f1d8 to your computer and use it in GitHub Desktop.
Concept for typesafe bit operations for register mappings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// this is part of a xpcc unittest: | |
// https://github.com/roboterclubaachen/xpcc/blob/develop/src/xpcc/architecture/peripheral/test/register_test.hpp#L20 | |
// more operations can be seen here: | |
// https://github.com/roboterclubaachen/xpcc/blob/develop/src/xpcc/architecture/peripheral/test/register_test.cpp#L16 | |
// complete macro definitions are available here: | |
// https://github.com/roboterclubaachen/xpcc/blob/develop/src/xpcc/architecture/peripheral/register.hpp#L55 | |
// see the type-safe registers in action here: | |
// https://github.com/roboterclubaachen/xpcc/blob/develop/src/xpcc/driver/inertial/lis302.hpp#L61 | |
// These are the register bit mappings | |
enum class | |
Test | |
{ | |
A = 0x01, | |
B = 0x02, | |
C = 0x04, | |
D = 0x08, | |
E = 0x10, | |
F = 0x20, | |
G = 0x40, | |
H = 0x80, | |
Mask = 0xff, | |
}; | |
REGISTER8(Test); | |
// these are bit mappings for a different register | |
enum class | |
Test2 | |
{ | |
a = 0x01, | |
b = 0x02, | |
c = 0x04, | |
d = 0x08, | |
e = 0x10, | |
f = 0x20, | |
g = 0x40, | |
h = 0x80, | |
Mask = 0xff, | |
}; | |
REGISTER8(Test2); | |
REGISTER8_GROUP(Common, Test, Test2); | |
// all typesafe | |
Test_t vD = Test::A | Test::B; | |
vD = vD | Test::C; | |
vD = Test::D | vD; | |
Test_t vI = Test::E; | |
vD = vD | vI; | |
// but still simple access of raw value without casting | |
uint8_t raw = vD.value; | |
// but Test2 and Test are not compatible!! | |
Test2_t e = Test::A | Test2::a; // NOT POSSIBLE | |
e = e | Test::A; // NOT possible either | |
e = e | vD; // NOT possible either | |
// possible | |
Common_t common = Test::A; | |
common = Test2::a; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// These are the register bit mappings | |
enum class | |
Test : uint8_t | |
{ | |
A = 0x01, | |
B = 0x02, | |
C = 0x04, | |
D = 0x08, | |
E = 0x10, | |
F = 0x20, | |
G = 0x40, | |
H = 0x80, | |
Mask = 0xff, | |
}; | |
// this is the register "type" | |
struct | |
Test_t : public ::xpcc::Register8 | |
{ | |
constexpr Test_t() {} | |
// explicit conversion constructor, ie. for static_cast<Type_t>(0x12) | |
explicit constexpr Test_t(uint8_t value) | |
: Register8(value) {} | |
// convert from enum class to type | |
constexpr Test_t(Test value) | |
: Register8(static_cast<uint8_t>(value)) {} | |
// Test | Test_t ~> Test_t | |
friend constexpr Test_t operator|(Test const &lhs, Test_t const &rhs) | |
{ | |
return Test_t(static_cast<Test>(static_cast<uint8_t>(lhs) | rhs.value)); | |
} | |
// Test_t | Test ~> Test_t | |
friend constexpr Test_t operator|(Test_t const &lhs, Test const &rhs) | |
{ | |
return Test_t(static_cast<Test>(static_cast<uint8_t>(rhs) | lhs.value)); | |
} | |
// Test_t | Test_t ~> Test_t | |
friend constexpr Test_t operator|(Test_t const &lhs, Test_t const &rhs) | |
{ | |
return Test_t(static_cast<Test>(lhs.value | rhs.value)); | |
} | |
}; | |
// Test | Test ~> Test_t | |
constexpr Test_t operator|(Test const &lhs, Test const &rhs) | |
{ | |
return Test_t(static_cast<Test>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs))); | |
} | |
// Declare Test2 exactly the same (abreviated) | |
... Test2 | |
... Test2_t | |
// common register group | |
struct Common_t : public ::xpcc::Register8 | |
{ | |
constexpr Common_t() {} | |
explicit constexpr Common_t(uint8_t value) | |
: Register8(value) {} | |
constexpr Common_t(Test value) \ | |
: Register(static_cast<uint8_t>(value)) {} \ | |
constexpr Common_t(Test_t value) \ | |
: Register(value.value) {} | |
constexpr Common_t(Test2 value) \ | |
: Register(static_cast<uint8_t>(value)) {} \ | |
constexpr Common_t(Test2_t value) \ | |
: Register(value.value) {} | |
}; | |
// all typesafe | |
Test_t vD = Test::A | Test::B; | |
vD = vD | Test::C; | |
vD = Test::D | vD; | |
Test_t vI = Test::E; | |
vD = vD | vI; | |
// but still simple access of raw value without casting | |
uint8_t raw = vD.value; | |
// but Test2 and Test are not compatible!! | |
Test2_t e = Test::A | Test2::a; // NOT POSSIBLE | |
e = e | Test::A; // NOT possible either | |
e = e | vD; // NOT possible either | |
// possible | |
Common_t common = Test::A; | |
common = Test2::a; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment