1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
#include <iostream>
#include <vector>
// ElementType should be an unsigned type.
template<typename ElementType, unsigned BitsPerValue>
class smalluint_array
{
// Assuming 8 bits per char.
static constexpr unsigned ValuesPerElement {sizeof(ElementType) * 8 / BitsPerValue};
static constexpr ElementType Mask {(ElementType(1) << BitsPerValue) - 1};
std::vector<ElementType> v;
public:
smalluint_array(size_t size)
: v((size + (ValuesPerElement-1)) / ValuesPerElement)
{ }
unsigned get(size_t i)
{
return (v[i/ValuesPerElement] >> (i%ValuesPerElement * BitsPerValue)) & Mask;
}
void set(size_t i, unsigned n)
{
unsigned x = i % ValuesPerElement * BitsPerValue;
v[i/ValuesPerElement] &= ElementType(-1) ^ (Mask << x);
v[i/ValuesPerElement] |= (n & Mask) << x;
}
};
int main()
{
using std::cout;
using uint4_array = smalluint_array<uint8_t, 4>;
using uint3_array = smalluint_array<uint64_t, 3>;
/*
For uint3_array: using uint8_t is 4.00 bits per value;
using uint16_t or uint32_t is 3.20 bits per value;
using uint64_t is 3.05 bits per value.
*/
uint4_array a(100);
for (unsigned n: {5, 1, 4, 6, 11, 15, 3, 8})
a.set(n, n);
for (unsigned n: {5, 1, 4, 6, 11, 15, 3, 8})
cout << a.get(n) << ' ';
cout << '\n';
size_t i = 0;
uint3_array b(100);
for (unsigned n: {5, 1, 4, 6, 3, 2, 7})
b.set(i++, n);
for (i = 0; i < 7; ++i)
cout << b.get(i) << ' ';
cout << '\n';
for (unsigned n: {0, 1, 2, 3, 4, 5, 6})
b.set(n, n);
for (i = 0; i < 7; ++i)
cout << b.get(i) << ' ';
cout << '\n';
}
| |