Bitmask depending on data type

1

I want to apply a bitmask to get only the upper half of bits. So for an uint32 it would be this:

uint32_t version_part = oldID & 0xFFFF0000;

This is all fine when the data type is hardcoded but if this was a templated function and I wanted to provide an arbritary data type (uint8_t, uint16_t, ...) I want to resize the bitmask proportionally (0xF0, 0xFF00, ...) and much preferably at compile time.

Given there is a finite number of data types I suppose you could just make if-cases (static if's?) but I was wondering if there is a nicer way to do it.

c++
bitmask
asked on Stack Overflow Jun 16, 2016 by KaiserJohaan

3 Answers

3

Does something like below solve your purpose?

template<typename T>
T maskbits(T oldID)
{
    const size_t SZ = sizeof oldID * CHAR_BIT;
    const T mask = (static_cast<T>((1ULL << (SZ / 2)) - 1ULL)) << (SZ / 2);
    return oldID & mask;
}
answered on Stack Overflow Jun 16, 2016 by Mohit Jain • edited Jun 16, 2016 by Mohit Jain
3

The answer of Mohit Jain is a good one. But since you're using templates, you could also do something with template specialisation:

/* general case */
template<typename T> class Mask {  };

/* specific cases */
template<> class Mask<uint16_t> {public: static const uint16_t value = 0xFF00; };
template<> class Mask<uint32_t> {public: static const uint32_t value = 0xFFFF0000; };
/* etc. */

template<typename T>
constexpr T maskbits(T uid)
{
    return uid & Mask<T>::value;
}

The big plus here is you can leave the general case blank to get a compile error on an unsupported type. Of course you could also make that calculate the mask, that depends on your needs.

answered on Stack Overflow Jun 16, 2016 by Joris • edited May 25, 2020 by Joris
1

Maybe you can try this, it will work for any integer size.

#include <iostream>

template<typename T>
T mask(T a = 0) {
    return (~T(0)) << 4*sizeof(T);
}

int main()
{
    unsigned char v = mask<unsigned char>();
    int v2 = mask(32);
    std::cout << "v = 0x" << std::hex << (unsigned int)v << std::endl;
    std::cout << "v2 = 0x" << std::hex << (unsigned int)v2 << std::endl;
}

The output is:

v = 0xf0
v2 = 0xffff0000

Edit: I just checked and with optimization enabled the compiler can produce the masks at compile time

answered on Stack Overflow Jun 16, 2016 by Benjamin Navarro • edited Jun 16, 2016 by Benjamin Navarro

User contributions licensed under CC BY-SA 3.0