Last active
February 2, 2024 02:47
-
-
Save RMDarth/6357ddd6e09b4117efe84fc3347a732a to your computer and use it in GitHub Desktop.
Compile-time size of the field in bit field struct (with C++11 restrictions)
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
// I've needed a constexpr way to get a size of the bit fields in struct (i.e. number of bits). | |
// Also, I needed it to work in Visual Studio 2015 (SP3), which is not yet fully support C++14, | |
// so constexpr functions could only use a single return statement and (almost) nothing more. | |
// After some time I've come up with this solution. It should work with any C++11 compiler. | |
// It has some limitations (it only works with unsigned fields). | |
// P.S.: With C++17 it could be done easier by using constexpr lambda expressions in macro. | |
#include <iostream> | |
#include <array> | |
// Helper constexpr functions | |
namespace BitFieldDetails | |
{ | |
template<typename T> | |
constexpr auto getBitsCount(T data, size_t startBit = 0) -> typename std::enable_if<std::is_unsigned<T>::value, size_t>::type | |
{ | |
return (startBit == sizeof(T) * 8) ? 0 : | |
getBitsCount(data, startBit + 1) + ((data & (1ull << startBit)) ? 1 : 0); | |
} | |
// We should support unsigned enums too | |
template<typename T> | |
constexpr auto getBitsCount(T data, size_t startBit = 0) -> typename std::enable_if<std::is_enum<T>::value, size_t>::type | |
{ | |
return (startBit == sizeof(T) * 8) ? 0 : | |
getBitsCount(data, startBit + 1) + ((static_cast<typename std::underlying_type<T>::type>(data) & (1ull << startBit)) ? 1 : 0); | |
} | |
#ifdef __clang__ | |
#pragma clang diagnostic push | |
#pragma clang diagnostic ignored "-Wbitfield-constant-conversion" | |
#endif | |
template<typename StructType, typename StructFieldsType, StructFieldsType ...initVals> | |
constexpr StructType getFilledStructImpl(StructType s, ...) | |
{ | |
return s; | |
} | |
template<typename StructType, typename StructFieldsType, StructFieldsType ...initVals> | |
constexpr StructType getFilledStructImpl(StructType s, decltype(StructType{ initVals... }, int()) = 0) | |
{ | |
// can you numeric_limits::max() here instead of -1, but it will require casting to and from underlying type for enum | |
return getFilledStructImpl<StructType, StructFieldsType, initVals..., | |
static_cast<StructFieldsType>(-1)> (StructType { initVals... }, 0); | |
} | |
template<typename StructType, typename StructFieldsType> | |
constexpr StructType getFilledStruct() | |
{ | |
using UnderlyingStructType = typename std::conditional< | |
std::is_enum<StructFieldsType>::value, | |
std::underlying_type<StructFieldsType>, | |
std::remove_cv<StructFieldsType>>::type::type; | |
static_assert(std::is_unsigned<UnderlyingStructType>::value, | |
"Bit field calculation only works with unsigned values"); | |
return getFilledStructImpl<StructType, StructFieldsType>(StructType{}, 0); | |
} | |
#ifdef __clang__ | |
#pragma clang diagnostic pop | |
#endif | |
} // namespace BitFieldDetails | |
// Main macro | |
#define bitsizeof(structType, fieldName) \ | |
::BitFieldDetails::getBitsCount(::BitFieldDetails::getFilledStruct<structType, decltype(structType{}.fieldName)>().fieldName) | |
// Structs to analyze | |
struct S1 | |
{ | |
uint16_t a : 2; | |
uint16_t b : 3; | |
uint16_t c : 7; | |
uint16_t d : 4; | |
}; | |
enum class SomeEnum : uint32_t | |
{ | |
Val1, | |
Val2, | |
Val3 | |
}; | |
struct S2 | |
{ | |
SomeEnum x : 20; | |
uint32_t y : 10; | |
uint32_t z : 2; | |
}; | |
int main() | |
{ | |
std::cout << bitsizeof(S1, c) << std::endl; // should output 7 | |
std::cout << bitsizeof(S2, x) << std::endl; // should output 20 | |
std::array<uint8_t, bitsizeof(S1, b)> arr{}; | |
std::cout << "Array size = " << arr.size() << std::endl; // should output Array size = 3 | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment