diff --git a/DataFormats/Headers/include/Headers/DataHeader.h b/DataFormats/Headers/include/Headers/DataHeader.h index 23a5b8d42d583..077dba2fb0cca 100644 --- a/DataFormats/Headers/include/Headers/DataHeader.h +++ b/DataFormats/Headers/include/Headers/DataHeader.h @@ -79,63 +79,186 @@ struct DataHeader; struct DataIdentifier; //__________________________________________________________________________________________________ +// internal implementations +/// @ingroup aliceo2_dataformat_tools +namespace Internal { +// terminating initializer implementation +template +constexpr T String2__() +{ + return 0; +} +// recursive initializer implementation +template +constexpr T String2__(char c, Targs... Fargs) +{ + return (T) c | String2__(Fargs...) << 8; +} + +/// compile time evaluation of the number of arguments in argument pack +template +struct getnargs { + static int const value = getnargs::value + 1; +}; +template +struct getnargs { + static int const value = 1; +}; + +/// get the number of active bits (set to 1) in a bitfield +template +struct NumberOfActiveBits { + static int const value = NumberOfActiveBits<(N >> 1)>::value + (N & 0x1); +}; +template <> +struct NumberOfActiveBits<0> { + static int const value = 0; +}; + +/// evaluate the array size necessary to hold a N-byte number with type T + template +struct ArraySize { + static_assert(N >= sizeof(T), "get this code to work first"); + static int const value = 1; + //static int const value = std::conditional<(N > sizeof(T)), ArraySize<(N - sizeof(T)), T>, ArraySize<0, T>>::value + 1; +}; +template +struct ArraySize<0, T> { + static int const value = 0; +}; + +/// select uint type depending on size, default is uint64_t +template +struct TraitsIntType { + typedef uint64_t type; +}; +template <> +struct TraitsIntType<1> { + typedef uint8_t type; +}; +template <> +struct TraitsIntType<2> { + typedef uint16_t type; +}; +template <> +struct TraitsIntType<4> { + typedef uint32_t type; +}; + +struct defaultPrinter { + void operator()(const char* str) const {} +}; +}; + +//__________________________________________________________________________________________________ +/// constexpr intializer, evaluated at compile time +/// generic intializer for variable char argument list +template +constexpr T String2(char c, Targs... Fargs) +{ + // number of arguments has either to match the size of the type, or the last element is treated + // as '0' if missing + static_assert(Internal::getnargs::value == sizeof(T) || + Internal::getnargs::value == sizeof(T) - 1, + "number of arguments does not match the uint type width" + ); + return Internal::String2__(c, Fargs...); +} + /// constexpr intializer, evaluated at compile time +/// backward compatibility, might be removed in the future constexpr uint64_t String2uint64(char c1, char c2, char c3, char c4, char c5, char c6, char c7, char c8) { - return((uint64_t) c1 | (uint64_t) c2 << 8 | (uint64_t) c3 << 16 | (uint64_t) c4 << 24 | - (uint64_t) c5 << 32 | (uint64_t) c6 << 40 | (uint64_t) c7 << 48 | (uint64_t) c8 << 56); + return String2(c1, c2, c3, c4, c5, c6, c7, c8); } /// constexpr intializer, evaluated at compile time -constexpr uint64_t String2uint64(const char* str, int pos=0) +/// generic initializer, convert a string to unsigned integer of different width +/// Example usage: String2("IDENTIFY") +/// @ingroup aliceo2_dataformat_tools +template +constexpr T String2(const char* str, int pos=0) { - return((uint64_t) str[0+pos] | - (str[0+pos] ? ((uint64_t) str[1+pos] << 8 | - (str[1+pos] ? ((uint64_t) str[2+pos] << 16 | - (str[2+pos] ? ((uint64_t) str[3+pos] << 24 | - (str[3+pos] ? ((uint64_t) str[4+pos] << 32 | - (str[4+pos] ? ((uint64_t) str[5+pos] << 40 | - (str[5+pos] ? ((uint64_t) str[6+pos] << 48 | - (str[6+pos] ? ((uint64_t) str[7+pos] << 56 ) + return((T) str[0+pos] | + (str[0+pos] && sizeof(T) >= 2 ? ((T) str[1+pos] << (sizeof(T) >= 2 ? 8 : 0) | + (str[1+pos] && sizeof(T) >= 4 ? ((T) str[2+pos] << (sizeof(T) >= 4 ? 16 : 0) | + (str[2+pos] && sizeof(T) >= 4 ? ((T) str[3+pos] << (sizeof(T) >= 4 ? 24 : 0) | + (str[3+pos] && sizeof(T) >= 8 ? ((T) str[4+pos] << (sizeof(T) >= 8 ? 32 : 0) | + (str[4+pos] && sizeof(T) >= 8 ? ((T) str[5+pos] << (sizeof(T) >= 8 ? 40 : 0) | + (str[5+pos] && sizeof(T) >= 8 ? ((T) str[6+pos] << (sizeof(T) >= 8 ? 48 : 0) | + (str[6+pos] && sizeof(T) >= 8 ? ((T) str[7+pos] << (sizeof(T) >= 8 ? 56 : 0) ) : 0)) : 0)) : 0)) : 0)) : 0)) : 0)) : 0)); } -/// constexpr intializer, evaluated at compile time -constexpr uint32_t String2uint32(char c1, char c2, char c3) +/// backward compatibility, can be removed +/// forwards to generic function +constexpr uint64_t String2uint64(const char* str, int pos=0) { - return((uint32_t) c1 | (uint32_t) c2 << 8 | (uint32_t) c3 << 16); + return String2(str, pos); } -/// constexpr intializer, evaluated at compile time -constexpr uint32_t String2uint32(const char* str) +/// backward compatibility, can be removed +/// forwards to generic function +constexpr uint32_t String2uint32(const char* str, int pos=0) { - return((uint32_t) str[0] | - (str[0] ? ((uint32_t) str[1] << 8 | - (str[1] ? ((uint32_t) str[2] << 16 | - (str[2] ? ((uint32_t) str[3] << 24 ) - :0 )) : 0)) : 0)); + return String2(str, pos); } + /// constexpr intializer, evaluated at compile time -constexpr uint32_t CharArr2uint32(char c1, char c2, char c3, char c4) +/// backward compatibility, might be removed in the future +constexpr uint32_t String2uint32(char c1, char c2, char c3) { - return((uint32_t) c1 | - (uint32_t) c2 << 8 | - (uint32_t) c3 << 16 | - (uint32_t) c4 << 24); + return String2(c1, c2, c3); } /// constexpr intializer, evaluated at compile time -constexpr uint32_t CharArr2uint32(const char* str) +/// backward compatibility, might be removed in the future +constexpr uint32_t CharArr2uint32(char c1, char c2, char c3, char c4) { - return((uint32_t) str[0] | - (str[0] ? ((uint32_t) str[1] << 8 | - (str[1] ? ((uint32_t) str[2] << 16 | - (str[2] ? ((uint32_t) str[3] << 24) - : 0)) : 0)) : 0)); + return String2(c1, c2, c3, c4); } +//__________________________________________________________________________________________________ +/// generic descriptor class faturing the union of a char and a uint element +/// of the same size +/// this is currently working only for up to 8 bytes aka uint64_t, the general +/// solution is working also for multiples of 64 bit, but then the itg member needs +/// to be an array for all. This has not been enabled yet, first the implications +/// have to be studied. +template +struct Descriptor { + static_assert(Internal::NumberOfActiveBits::value == 1 && N <= 8, + "size is required to be 1 or a multiple of 2"); + static int const size = N; + static int const bitcount = size*8; + static int const arraySize = 1; //Internal::ArraySize::value; + typedef typename Internal::TraitsIntType::type ItgType; + + union { + char str[N]; + ItgType itg; // for extension > 64 bit: [arraySize]; + }; + Descriptor() {}; + Descriptor(const Descriptor& other) : itg(other.itg) {} + Descriptor& operator=(const Descriptor& other) { + if (&other != this) itg = other.itg; + return *this; + } + // note: no operator=(const char*) as this potentially runs into trouble with this + // general pointer type, use: somedescriptor = Descriptor("DESCRIPTION") + constexpr Descriptor(const char* origin) : itg(String2(origin)) {}; + bool operator==(const Descriptor& other) const {return itg == other.itg;} + bool operator!=(const Descriptor& other) const {return not this->operator==(other);} + // print function needs to be implemented for every derivation + PrinterPolicy printer; + void print() const { + // eventually terminate string before printing + printer(str); + }; +}; + //__________________________________________________________________________________________________ /// default int representation of 'invalid' token for 4-byte char field const uint32_t gInvalidToken32 = 0xFFFFFFFF; @@ -439,24 +562,10 @@ struct DataDescription { //__________________________________________________________________________________________________ // 32bit (4 characters) for data origin, ex. the detector or subsystem name -struct DataOrigin { - union { - char str[gSizeDataOriginString]; - uint32_t itg; - }; - DataOrigin(); - DataOrigin(const DataOrigin& other) : itg(other.itg) {} - DataOrigin& operator=(const DataOrigin& other) { - if (&other != this) itg = other.itg; - return *this; - } - // note: no operator=(const char*) as this potentially runs into trouble with this - // general pointer type, use: someorigin = DataOrigin("BLA") - constexpr DataOrigin(const char* origin) : itg{String2uint32(origin)} {}; - bool operator==(const DataOrigin&) const; - bool operator!=(const DataOrigin& other) const {return not this->operator==(other);} - void print() const; +struct printDataOrigin { + void operator()(const char* str) const; }; +typedef Descriptor DataOrigin; //__________________________________________________________________________________________________ /// @struct DataHeader diff --git a/DataFormats/Headers/src/DataHeader.cxx b/DataFormats/Headers/src/DataHeader.cxx index d2c27e5510fd6..d4481066d6eda 100644 --- a/DataFormats/Headers/src/DataHeader.cxx +++ b/DataFormats/Headers/src/DataHeader.cxx @@ -15,7 +15,7 @@ #include // strncpy //the answer to life and everything -const uint32_t AliceO2::Header::BaseHeader::sMagicString = CharArr2uint32("O2O2"); +const uint32_t AliceO2::Header::BaseHeader::sMagicString = String2("O2O2"); //possible serialization types const AliceO2::Header::SerializationMethod AliceO2::Header::gSerializationMethodAny ("*******"); @@ -176,16 +176,7 @@ bool AliceO2::Header::DataHeader::operator==(const DataHeader& that) const } //__________________________________________________________________________________________________ -AliceO2::Header::DataOrigin::DataOrigin() : itg(gInvalidToken32) {} - -//__________________________________________________________________________________________________ -bool AliceO2::Header::DataOrigin::operator==(const DataOrigin& other) const -{ - return itg == other.itg; -} - -//__________________________________________________________________________________________________ -void AliceO2::Header::DataOrigin::print() const +void AliceO2::Header::printDataOrigin::operator()(const char* str) const { printf("Data origin : %s\n", str); }