Gaia-ECS v0.9.3
A simple and powerful entity component system
Loading...
Searching...
No Matches
bitset_iterator.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cstdint>
5#include <type_traits>
6
7namespace gaia {
8 namespace cnt {
13 template <typename TBitset, bool IsFwd, bool IsInverse>
15 public:
16 using value_type = uint32_t;
17 using size_type = typename TBitset::size_type;
18
19 private:
20 const TBitset* m_bitset = nullptr;
21 value_type m_pos = 0;
22
23 GAIA_NODISCARD size_type item(uint32_t wordIdx) const noexcept {
24 if constexpr (IsInverse)
25 return ~m_bitset->data(wordIdx);
26 else
27 return m_bitset->data(wordIdx);
28 }
29
30 GAIA_NODISCARD bool check_bit(uint32_t pos) const noexcept {
31 if constexpr (IsInverse)
32 return !m_bitset->test(pos);
33 else
34 return m_bitset->test(pos);
35 }
36
37 GAIA_NODISCARD uint32_t find_next_set_bit(uint32_t pos) const noexcept {
38 value_type wordIndex = pos / TBitset::BitsPerItem;
39 const auto item_count = m_bitset->items();
40 GAIA_ASSERT(wordIndex < item_count);
41 size_type word = 0;
42
43 const size_type posInWord = pos % TBitset::BitsPerItem + 1;
44 if GAIA_LIKELY (posInWord < TBitset::BitsPerItem) {
45 const size_type mask = (size_type(1) << posInWord) - 1;
46 word = item(wordIndex) & (~mask);
47 }
48
49 GAIA_MSVC_WARNING_PUSH()
50 GAIA_MSVC_WARNING_DISABLE(4244)
51 while (true) {
52 if (word != 0) {
53 if constexpr (TBitset::BitsPerItem == 32)
54 return wordIndex * TBitset::BitsPerItem + GAIA_FFS(word) - 1;
55 else
56 return wordIndex * TBitset::BitsPerItem + GAIA_FFS64(word) - 1;
57 }
58
59 // No set bit in the current word, move to the next one
60 if (++wordIndex >= item_count)
61 return pos;
62
63 word = item(wordIndex);
64 }
65 GAIA_MSVC_WARNING_POP()
66 }
67
68 GAIA_NODISCARD uint32_t find_prev_set_bit(uint32_t pos) const noexcept {
69 value_type wordIndex = pos / TBitset::BitsPerItem;
70 GAIA_ASSERT(wordIndex < m_bitset->items());
71
72 const size_type posInWord = pos % TBitset::BitsPerItem;
73 const size_type mask = (size_type(1) << posInWord) - 1;
74 size_type word = item(wordIndex) & mask;
75
76 GAIA_MSVC_WARNING_PUSH()
77 GAIA_MSVC_WARNING_DISABLE(4244)
78 while (true) {
79 if (word != 0) {
80 if constexpr (TBitset::BitsPerItem == 32)
81 return TBitset::BitsPerItem * (wordIndex + 1) - GAIA_CTZ(word) - 1;
82 else
83 return TBitset::BitsPerItem * (wordIndex + 1) - GAIA_CTZ64(word) - 1;
84 }
85
86 // No set bit in the current word, move to the previous one
87 if (wordIndex == 0)
88 return pos;
89
90 word = item(--wordIndex);
91 }
92 GAIA_MSVC_WARNING_POP()
93 }
94
95 public:
96 bitset_const_iterator() = default;
97 bitset_const_iterator(const TBitset& bitset, value_type pos, bool fwd): m_bitset(&bitset), m_pos(pos) {
98 if (fwd) {
99 if constexpr (!IsFwd) {
100 // Find the first set bit
101 if (pos != 0 || !check_bit(0)) {
102 pos = find_next_set_bit(m_pos);
103 // Point before the last item if no set bit was found
104 if (pos == m_pos)
105 pos = (value_type)-1;
106 else
107 --pos;
108 } else
109 --pos;
110 } else {
111 // Find the first set bit
112 if (pos != 0 || !check_bit(0)) {
113 pos = find_next_set_bit(m_pos);
114 // Point beyond the last item if no set bit was found
115 if (pos == m_pos)
116 pos = bitset.size();
117 }
118 }
119 m_pos = pos;
120 } else {
121 const auto bitsetSize = bitset.size();
122 const auto lastBit = bitsetSize - 1;
123
124 // Stay inside bounds
125 if (pos >= bitsetSize)
126 pos = bitsetSize - 1;
127
128 if constexpr (!IsFwd) {
129 // Find the last set bit
130 if (pos != lastBit || !check_bit(pos)) {
131 const auto newPos = find_prev_set_bit(pos);
132 // Point one beyond the last found bit
133 pos = (newPos == pos) ? bitsetSize - 1 : newPos;
134 }
135 } else {
136 // Find the last set bit
137 if (pos != lastBit || !check_bit(pos)) {
138 const auto newPos = find_prev_set_bit(pos);
139 // Point one beyond the last found bit
140 pos = (newPos == pos) ? bitsetSize : newPos + 1;
141 }
142 // Point one beyond the last found bit
143 else
144 ++pos;
145 }
146
147 m_pos = pos;
148 }
149 }
150
151 GAIA_NODISCARD value_type operator*() const {
152 return m_pos;
153 }
154
155 GAIA_NODISCARD value_type operator->() const {
156 return m_pos;
157 }
158
159 GAIA_NODISCARD value_type index() const {
160 return m_pos;
161 }
162
163 bitset_const_iterator& operator++() {
164 if constexpr (!IsFwd) {
165 if (m_pos == (value_type)-1)
166 return *this;
167
168 auto newPos = find_prev_set_bit(m_pos);
169 // Point one past the last item if no new bit was found
170 if (newPos == m_pos)
171 --newPos;
172 m_pos = newPos;
173 } else {
174 auto newPos = find_next_set_bit(m_pos);
175 // Point one past the last item if no new bit was found
176 if (newPos == m_pos)
177 ++newPos;
178 m_pos = newPos;
179 }
180
181 return *this;
182 }
183
184 GAIA_NODISCARD bitset_const_iterator operator++(int) {
185 bitset_const_iterator temp(*this);
186 ++*this;
187 return temp;
188 }
189
190 GAIA_NODISCARD bool operator==(const bitset_const_iterator& other) const {
191 return m_pos == other.m_pos;
192 }
193
194 GAIA_NODISCARD bool operator!=(const bitset_const_iterator& other) const {
195 return m_pos != other.m_pos;
196 }
197 };
198
199 template <typename TBitset>
201 template <typename TBitset>
203 template <typename TBitset>
205 template <typename TBitset>
207 } // namespace cnt
208} // namespace gaia
Bitset iterator.
Definition bitset_iterator.h:14
Definition bitset.h:12
GAIA_NODISCARD constexpr uint32_t size() const
Returns the number of bits the bitset can hold.
Definition bitset.h:259
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9