summaryrefslogtreecommitdiff
path: root/include/util/bitset.hpp
blob: cd1dbd029e985c205c33088fa8e4a95a4c5bf1aa (plain)
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#pragma once

#include <array>
#include <cassert>
#include <cstdint>
#include <vector>

constexpr int bits_ceil(int bits)
{
	return bits / 8 + (bits % 8 > 0 ? 1 : 0);
}

template <unsigned int flags, auto size = bits_ceil(flags)>
struct bitset : std::array<std::uint8_t, size> {
	using array_type = std::array<std::uint8_t, size>;

private:
	struct bit_ref {
		bitset<flags>& a;
		int referenced_byte;
		uint8_t referenced_bit_mask;

		bool operator=(bool b)
		{
			if (b)
				a.at(referenced_byte) |= referenced_bit_mask;
			else
				a.at(referenced_byte) &= ~referenced_bit_mask;
			return b;
		}

		constexpr operator bool() const
		{
			return (a.at(referenced_byte) & referenced_bit_mask) > 0;
		}
	};

public:
	template <class T>
	constexpr bool operator[](T idx) const
	{
		unsigned int i = (unsigned int)(idx);
		assert(i < flags);
		return (array_type::at(i / 8) & (1 << (i % 8))) > 0;
	}

	template <class T>
	bit_ref operator[](T idx)
	{
		unsigned int i = (unsigned int)(idx);
		assert(i < flags);
		return bit_ref(*this, i / 8, (1 << (i % 8)));
	}
};

// FIXME: ??
template <>
struct bitset<0> : std::vector<std::uint8_t> {
	using container_type = std::vector<std::uint8_t>;

private:
	struct bit_ref {
		bitset<0>& a;
		int referenced_byte;
		uint8_t referenced_bit_mask;

		bool operator=(bool b)
		{
			if (b)
				a.at(referenced_byte) |= referenced_bit_mask;
			else
				a.at(referenced_byte) &= ~referenced_bit_mask;
			return b;
		}

		constexpr operator bool() const
		{
			return (a.at(referenced_byte) & referenced_bit_mask) > 0;
		}
	};

public:
	template <class T>
	constexpr bool operator[](T idx) const
	{
		unsigned int i = (unsigned int)(idx);
		assert(i < container_type::size());
		return (container_type::at(i / 8) & (1 << (i % 8))) > 0;
	}

	template <class T>
	bit_ref operator[](T idx)
	{
		unsigned int i = (unsigned int)(idx);
		assert(i < container_type::size());
		return bit_ref(*this, i / 8, (1 << (i % 8)));
	}
};