The Sparta Modeling Framework
Loading...
Searching...
No Matches
BitArray.hpp
1/*
2 */
3#pragma once
4
5#include <vector>
6#include <iomanip>
7#include <type_traits>
8#include <algorithm>
9
11
12namespace sparta {
13 namespace utils {
14
15 template <class InputIterator,
16 class OutputIterator,
17 class T,
18 class UnaryOperation>
19 static OutputIterator slide(InputIterator first,
20 InputIterator last,
21 OutputIterator result,
22 T init,
23 UnaryOperation operation)
24 {
25 if (first == last) {
26 return result;
27 }
28
29 for (; first + 1 != last; ++first, ++result) {
30 *result = operation(*first, *(first + 1));
31 }
32 *result = operation(*first, init);
33
34 return result;
35 }
36
45 {
46 private:
47 using data_type = uint8_t;
48
49 public:
60 BitArray(const void *data, size_t data_size, size_t array_size = 0)
61 {
62 if (!array_size) {
63 array_size = data_size;
64 }
65
66 initializeStorage_(roundUpTo_(array_size, sizeof(data_type)));
67 std::memcpy(data_, data, std::min(data_size, array_size));
68 }
69
79 template <typename T,
80 typename = typename std::enable_if<std::is_integral<T>::value>::type>
81 explicit BitArray(const T &value, size_t array_size = sizeof(T))
82 : BitArray(reinterpret_cast<const void *>(&value), sizeof(T), array_size)
83 {
84 }
85
86 BitArray(const BitArray &other)
87 {
88 initializeStorage_(other.data_size_);
89 std::copy(other.data_, other.data_ + data_size_, data_);
90 }
91
92 BitArray &operator=(const BitArray &other) = default;
93
94 BitArray(BitArray &&) = default;
95
96 BitArray &operator=(BitArray &&) = default;
97
98 const void *getValue() const
99 {
100 return data_;
101 }
102
103 template <typename T,
104 typename = typename std::enable_if<std::is_integral<T>::value>::type>
105 T getValue() const
106 {
107 T tmp = 0;
108 std::memcpy(&tmp, data_, std::min(sizeof(T), data_size_));
109 return tmp;
110 }
111
112 size_t getSize() const
113 {
114 return data_size_ * sizeof(data_type);
115 }
116
120 template <typename T,
121 typename = typename std::enable_if<std::is_integral<T>::value>::type>
122 void fill(const T &value)
123 {
124 for (size_t i = 0; i < getSize(); ++i) {
125 const auto shift = 8 * (i % sizeof(T));
126 data_[i] = (value >> shift) & 0xff;
127 }
128 }
129
130 bool operator==(const BitArray &other) const
131 {
132 return (data_size_ == other.data_size_) &&
133 std::equal(data_, data_ + data_size_, other.data_);
134 }
135
136 bool operator!=(const BitArray &other) const
137 {
138 return !(*this == other);
139 }
140
141 BitArray operator<<(size_t amount) const
142 {
143 BitArray res(*this);
144 shiftLeft_(res, amount);
145 return res;
146 }
147
148 BitArray &operator<<=(size_t amount)
149 {
150 shiftLeft_(*this, amount);
151 return *this;
152 }
153
154 BitArray operator>>(size_t amount) const
155 {
156 BitArray res(*this);
157 shiftRight_(res, amount);
158 return res;
159 }
160
161 BitArray &operator>>=(size_t amount)
162 {
163 shiftRight_(*this, amount);
164 return *this;
165 }
166
174 BitArray operator&(const BitArray &other) const
175 {
176 BitArray res(*this);
177 and_(res, other);
178 return res;
179 }
180
181 BitArray &operator&=(const BitArray &other)
182 {
183 and_(*this, other);
184 return *this;
185 }
186
194 BitArray operator|(const BitArray &other) const
195 {
196 BitArray res(*this);
197 or_(res, other);
198 return res;
199 }
200
201 BitArray &operator|=(const BitArray &other)
202 {
203 or_(*this, other);
204 return *this;
205 }
206
207 BitArray operator~() const
208 {
209 BitArray res(*this);
210 negate_(res);
211 return res;
212 }
213
214 private:
215 void initializeStorage_(size_t data_size)
216 {
217 /* This method should only be called once at construction */
218 sparta_assert(data_size_ == 0);
219 sparta_assert(data_ == nullptr);
220
221 if (data_size > SMALL_OPTIMIZATION_SIZE) {
222 data_ls_.resize(data_size, 0);
223 data_ = &data_ls_[0];
224 } else {
225 data_ = data_ss_;
226 }
227
228 /* Update size after allocating data to maintain the invariant that
229 * data_size_ matches the allocated memory size in case new throws */
230 data_size_ = data_size;
231 }
232
233 static size_t roundUpTo_(size_t value, size_t target)
234 {
235 return (value + target - 1) / target;
236 }
237
238 static void shiftLeft_(BitArray &array, size_t amount)
239 {
240 const auto bits_per_word = 8 * sizeof(data_type);
241
242 shiftLeftWords_(array, amount / bits_per_word);
243 shiftLeftBits_(array, amount % bits_per_word);
244 }
245
246 static void shiftLeftWords_(BitArray &array, size_t amount)
247 {
248 const auto first = array.data_;
249 const auto last = array.data_ + array.data_size_;
250
251 std::rotate(first, last - amount, last);
252 std::fill(first, first + amount, 0);
253 }
254
255 static void shiftLeftBits_(BitArray &array, size_t bits)
256 {
257 const auto rbegin =
258 std::reverse_iterator<data_type *>(array.data_ + array.data_size_);
259 const auto rend = std::reverse_iterator<data_type *>(array.data_);
260
261 slide(rbegin, rend, rbegin, data_type(0),
262 [bits](data_type low, data_type high)
263 {
264 return low << bits | high >> (8 * sizeof(data_type) - bits);
265 });
266 }
267
268 static void shiftRight_(BitArray &array, size_t amount)
269 {
270 const auto bits_per_word = 8 * sizeof(data_type);
271
272 shiftRightWords_(array, amount / bits_per_word);
273 shiftRightBits_(array, amount % bits_per_word);
274 }
275
276 static void shiftRightWords_(BitArray &array, size_t amount)
277 {
278 const auto first = array.data_;
279 const auto last = array.data_ + array.data_size_;
280
281 std::rotate(first, first + amount, last);
282 std::fill(last - amount, last, 0);
283 }
284
285 static void shiftRightBits_(BitArray &array, size_t bits)
286 {
287 const auto begin = array.data_;
288 const auto end = array.data_ + array.data_size_;
289
290 slide(begin, end, begin, data_type(0),
291 [bits](data_type low, data_type high)
292 {
293 return low >> bits | high << (8 * sizeof(data_type) - bits);
294 });
295 }
296
297 static void and_(BitArray &array, const BitArray &other)
298 {
299 const auto min_size =
300 std::min(array.getSize(), other.getSize());
301
302 for (size_t i = 0; i < min_size; i++) {
303 array.data_[i] &= other.data_[i];
304 }
305 }
306
307 static void or_(BitArray &array, const BitArray &other)
308 {
309 const auto min_size =
310 std::min(array.getSize(), other.getSize());
311
312 for (size_t i = 0; i < min_size; i++) {
313 array.data_[i] |= other.data_[i];
314 }
315 }
316
317 static void negate_(BitArray &array)
318 {
319 for (size_t i = 0; i < array.data_size_; i++) {
320 array.data_[i] = ~array.data_[i];
321 }
322 }
323
324 static const size_t SMALL_OPTIMIZATION_SIZE = 16;
325
327 std::vector<data_type> data_ls_;
328
330 data_type data_ss_[SMALL_OPTIMIZATION_SIZE / sizeof(data_type)] = {0};
331
333 data_type *data_ = nullptr;
334
336 size_t data_size_ = 0;
337 };
338
339 } /* namespace utils */
340} /* namespace sparta */
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Class for fast bit manipulation.
Definition BitArray.hpp:45
BitArray(const void *data, size_t data_size, size_t array_size=0)
Definition BitArray.hpp:60
BitArray operator|(const BitArray &other) const
Definition BitArray.hpp:194
void fill(const T &value)
Definition BitArray.hpp:122
BitArray(const T &value, size_t array_size=sizeof(T))
Definition BitArray.hpp:81
BitArray operator&(const BitArray &other) const
Definition BitArray.hpp:174
Macros for handling exponential backoff.