The purpose for this class is to pack two 4 bit unsigned integer into 8 bit unsigned integer, e.g. uint8_t
.
It is made in a way, so the class to resemble array of two contiguous elements.
Once this work correctly, one may program continuous array of 4 bit integers and to use it for example for counting bloom filter.
A "special" proxy class is used in a way similar to std::vector, so you can do:
UINT4 x;
// set parts
x[0] = 1; // set first part, OK
x[1] = 20; // set second part, OK
// convert to uint8_t
uint8_t i = x[0]; // OK
// arithmetic mostly works.
++x[0]; // OK
x[0] += 10; // OK
--x[1]; // OK
x[1] -= 10; // OK
// not implemented yet, mostly because I don't need it
// x[1] = x[0] + 10;
#include <cstdint>
//#include <type_traits>
//#include <cstdio>
class UINT4{
uint8_t _0 : 4;
uint8_t _1 : 4;
class Proxy;
public:
constexpr explicit UINT4() : UINT4{ 0, 0 }{
}
constexpr UINT4(uint8_t _0, uint8_t _1) : _0{ _0 }, _1{ _1 }{
}
constexpr
Proxy operator[](std::size_t i);
constexpr uint8_t operator[](std::size_t i) const{
if (i == 0)
return _0;
else
return _1;
}
};
static_assert(sizeof(UINT4) == 1);
class UINT4::Proxy{
UINT4 &d;
uint8_t i;
public:
// c-tor
constexpr Proxy(UINT4 &d, std::size_t i) :
d(d ),
i(i == 0 ? 0 : 1 ){
}
// convert
constexpr operator uint8_t() const{
// we can use UINT4::operator[](size_t) const
if (i == 0)
return d._0;
else
return d._1;
}
// compare
constexpr bool operator==(uint8_t x) const{
if (i == 0)
return d._0 == x;
else
return d._1 == x;
}
constexpr bool operator!=(uint8_t x) const{
return !( *this == x );
}
constexpr bool operator<(uint8_t x) const{
if (i == 0)
return d._0 < x;
else
return d._1 < x;
}
constexpr bool operator<=(uint8_t x) const{
if (i == 0)
return d._0 <= x;
else
return d._1 <= x;
}
constexpr bool operator>(uint8_t x) const{
return !( *this <= x );
}
constexpr bool operator>=(uint8_t x) const{
return !( *this < x );
}
// assign
constexpr
auto &operator=(uint8_t x){
if (i == 0)
d._0 = x;
else
d._1 = x;
return *this;
}
// +++
constexpr
auto &operator+=(uint8_t x){
if (i == 0)
d._0 += x;
else
d._1 += x;
return *this;
}
constexpr
auto &operator++(){
return *this += uint8_t{ 1 };
}
// can not be done easily, because there are references
// auto operator++(int);
// ---
constexpr
auto &operator-=(uint8_t x){
return *this += - x;
}
constexpr
auto &operator--(){
return *this -= uint8_t{ 1 };
}
// can not be done easily, because there are references
// auto operator--(int);
// todo add multiplication and division
};
constexpr auto UINT4::operator[](std::size_t i) -> Proxy{
return Proxy{ *this, i };
}
#include <cstdio>
int main(){
UINT4 x{ 15, 0 };
x[1] = 2;
uint8_t a = x[0];
printf("%u\n", a);
printf("%u %u\n", uint16_t{ x[0] }, uint16_t{ x[1] } );
x[0] -= 10;
x[1] += 10;
printf("%u %u\n", uint16_t{ x[0] }, uint16_t{ x[1] } );
++x[0];
--x[1];
printf("%u %u\n", uint16_t{ x[0] }, uint16_t{ x[1] } );
}