Branch data Line data Source code
1 : : // Copyright (c) 2022 The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #ifndef BITCOIN_UTIL_BITDEQUE_H
6 : : #define BITCOIN_UTIL_BITDEQUE_H
7 : :
8 : : #include <bitset>
9 : : #include <cstddef>
10 : : #include <deque>
11 : : #include <limits>
12 : : #include <stdexcept>
13 : : #include <tuple>
14 : :
15 : : /** Class that mimics std::deque<bool>, but with std::vector<bool>'s bit packing.
16 : : *
17 : : * BITS_PER_WORD selects the (minimum) number of bits that are allocated at once.
18 : : * Larger values reduce the asymptotic memory usage overhead, at the cost of
19 : : * needing larger up-front allocations. The default is 4096 bytes.
20 : : */
21 : : template<int BITS_PER_WORD = 4096 * 8>
22 : : class bitdeque
23 : : {
24 : : // Internal definitions
25 : : using word_type = std::bitset<BITS_PER_WORD>;
26 : : using deque_type = std::deque<word_type>;
27 : : static_assert(BITS_PER_WORD > 0);
28 : :
29 : : // Forward and friend declarations of iterator types.
30 : : template<bool Const> class Iterator;
31 : : template<bool Const> friend class Iterator;
32 : :
33 : : /** Iterator to a bitdeque element, const or not. */
34 : : template<bool Const>
35 : : class Iterator
36 : : {
37 : : using deque_iterator = std::conditional_t<Const, typename deque_type::const_iterator, typename deque_type::iterator>;
38 : :
39 : : deque_iterator m_it;
40 : : int m_bitpos{0};
41 : 11503088 : Iterator(const deque_iterator& it, int bitpos) : m_it(it), m_bitpos(bitpos) {}
42 : : friend class bitdeque;
43 : :
44 : : public:
45 : : using iterator_category = std::random_access_iterator_tag;
46 : : using value_type = bool;
47 : : using pointer = void;
48 : : using const_pointer = void;
49 : : using reference = std::conditional_t<Const, bool, typename word_type::reference>;
50 : : using const_reference = bool;
51 : : using difference_type = std::ptrdiff_t;
52 : :
53 : : /** Default constructor. */
54 : : Iterator() = default;
55 : :
56 : : /** Default copy constructor. */
57 : 217097867 : Iterator(const Iterator&) = default;
58 : :
59 : : /** Conversion from non-const to const iterator. */
60 : : template<bool ConstArg = Const, typename = std::enable_if_t<Const && ConstArg>>
61 : 69372 : Iterator(const Iterator<false>& x) : m_it(x.m_it), m_bitpos(x.m_bitpos) {}
62 : :
63 : 21446214 : Iterator& operator+=(difference_type dist)
64 : : {
65 [ - + ]: 21446214 : if (dist > 0) {
[ + + + + ]
66 [ # # ]: 606795 : if (dist + m_bitpos >= BITS_PER_WORD) {
[ + + + + ]
67 : 369231 : ++m_it;
68 : 369231 : dist -= BITS_PER_WORD - m_bitpos;
69 : 369231 : m_bitpos = 0;
70 : 369231 : }
71 : 606795 : auto jump = dist / BITS_PER_WORD;
72 : 606795 : m_it += jump;
73 : 606795 : m_bitpos += dist - jump * BITS_PER_WORD;
74 [ - + ]: 21446214 : } else if (dist < 0) {
[ + + + + ]
75 : 20410270 : dist = -dist;
76 [ + + ]: 20410270 : if (dist > m_bitpos) {
[ + + + + ]
77 : 10363392 : --m_it;
78 : 10363392 : dist -= m_bitpos + 1;
79 : 10363392 : m_bitpos = BITS_PER_WORD - 1;
80 : 10363392 : }
81 : 20410270 : auto jump = dist / BITS_PER_WORD;
82 : 20410270 : m_it -= jump;
83 : 20410270 : m_bitpos -= dist - jump * BITS_PER_WORD;
84 : 20410270 : }
85 : 21446214 : return *this;
86 : : }
87 : :
88 : 452758 : friend difference_type operator-(const Iterator& x, const Iterator& y)
89 : : {
90 : 452758 : return BITS_PER_WORD * (x.m_it - y.m_it) + x.m_bitpos - y.m_bitpos;
91 : : }
92 : :
93 : : Iterator& operator=(const Iterator&) = default;
94 : 10519731 : Iterator& operator-=(difference_type dist) { return operator+=(-dist); }
95 [ + + ]: 259612133 : Iterator& operator++() { ++m_bitpos; if (m_bitpos == BITS_PER_WORD) { m_bitpos = 0; ++m_it; }; return *this; }
96 : 181987052 : Iterator operator++(int) { auto ret{*this}; operator++(); return ret; }
97 [ + + ]: 74035511 : Iterator& operator--() { if (m_bitpos == 0) { m_bitpos = BITS_PER_WORD; --m_it; }; --m_bitpos; return *this; }
98 : : Iterator operator--(int) { auto ret{*this}; operator--(); return ret; }
99 : 10919462 : friend Iterator operator+(Iterator x, difference_type dist) { x += dist; return x; }
100 : : friend Iterator operator+(difference_type dist, Iterator x) { x += dist; return x; }
101 : 10515190 : friend Iterator operator-(Iterator x, difference_type dist) { x -= dist; return x; }
102 : : friend bool operator<(const Iterator& x, const Iterator& y) { return std::tie(x.m_it, x.m_bitpos) < std::tie(y.m_it, y.m_bitpos); }
103 : : friend bool operator>(const Iterator& x, const Iterator& y) { return std::tie(x.m_it, x.m_bitpos) > std::tie(y.m_it, y.m_bitpos); }
104 : : friend bool operator<=(const Iterator& x, const Iterator& y) { return std::tie(x.m_it, x.m_bitpos) <= std::tie(y.m_it, y.m_bitpos); }
105 : : friend bool operator>=(const Iterator& x, const Iterator& y) { return std::tie(x.m_it, x.m_bitpos) >= std::tie(y.m_it, y.m_bitpos); }
106 [ - + - + ]: 175296 : friend bool operator==(const Iterator& x, const Iterator& y) { return x.m_it == y.m_it && x.m_bitpos == y.m_bitpos; }
107 [ + + ]: 52847337 : friend bool operator!=(const Iterator& x, const Iterator& y) { return x.m_it != y.m_it || x.m_bitpos != y.m_bitpos; }
108 : 343827236 : reference operator*() const { return (*m_it)[m_bitpos]; }
109 : 10133334 : reference operator[](difference_type pos) const { return *(*this + pos); }
110 : : };
111 : :
112 : : public:
113 : : using value_type = bool;
114 : : using size_type = std::size_t;
115 : : using difference_type = typename deque_type::difference_type;
116 : : using reference = typename word_type::reference;
117 : : using const_reference = bool;
118 : : using iterator = Iterator<false>;
119 : : using const_iterator = Iterator<true>;
120 : : using pointer = void;
121 : : using const_pointer = void;
122 : : using reverse_iterator = std::reverse_iterator<iterator>;
123 : : using const_reverse_iterator = std::reverse_iterator<const_iterator>;
124 : :
125 : : private:
126 : : /** Deque of bitsets storing the actual bit data. */
127 : : deque_type m_deque;
128 : :
129 : : /** Number of unused bits at the front of m_deque.front(). */
130 : : int m_pad_begin;
131 : :
132 : : /** Number of unused bits at the back of m_deque.back(). */
133 : : int m_pad_end;
134 : :
135 : : /** Shrink the container by n bits, removing from the end. */
136 : 146752 : void erase_back(size_type n)
137 : : {
138 [ + + ]: 146752 : if (n >= static_cast<size_type>(BITS_PER_WORD - m_pad_end)) {
139 : 10018 : n -= BITS_PER_WORD - m_pad_end;
140 : 10018 : m_pad_end = 0;
141 : 10018 : m_deque.erase(m_deque.end() - 1 - (n / BITS_PER_WORD), m_deque.end());
142 : 10018 : n %= BITS_PER_WORD;
143 : 10018 : }
144 [ + + ]: 146752 : if (n) {
145 : 133397 : auto& last = m_deque.back();
146 [ + + ]: 12166015 : while (n) {
147 : 12032618 : last.reset(BITS_PER_WORD - 1 - m_pad_end);
148 : 12032618 : ++m_pad_end;
149 : 12032618 : --n;
150 : : }
151 : 133397 : }
152 : 146752 : }
153 : :
154 : : /** Extend the container by n bits, adding at the end. */
155 : 10138723 : void extend_back(size_type n)
156 : : {
157 [ + + ]: 10138723 : if (n > static_cast<size_type>(m_pad_end)) {
158 : 116383 : n -= m_pad_end + 1;
159 : 116383 : m_pad_end = BITS_PER_WORD - 1;
160 : 116383 : m_deque.insert(m_deque.end(), 1 + (n / BITS_PER_WORD), {});
161 : 116383 : n %= BITS_PER_WORD;
162 : 116383 : }
163 : 10138723 : m_pad_end -= n;
164 : 10138723 : }
165 : :
166 : : /** Shrink the container by n bits, removing from the beginning. */
167 : 27947 : void erase_front(size_type n)
168 : : {
169 [ + + ]: 27947 : if (n >= static_cast<size_type>(BITS_PER_WORD - m_pad_begin)) {
170 : 9517 : n -= BITS_PER_WORD - m_pad_begin;
171 : 9517 : m_pad_begin = 0;
172 : 9517 : m_deque.erase(m_deque.begin(), m_deque.begin() + 1 + (n / BITS_PER_WORD));
173 : 9517 : n %= BITS_PER_WORD;
174 : 9517 : }
175 [ + + ]: 27947 : if (n) {
176 : 20948 : auto& first = m_deque.front();
177 [ + + ]: 531486 : while (n) {
178 : 510538 : first.reset(m_pad_begin);
179 : 510538 : ++m_pad_begin;
180 : 510538 : --n;
181 : : }
182 : 20948 : }
183 : 27947 : }
184 : :
185 : : /** Extend the container by n bits, adding at the beginning. */
186 : 64305 : void extend_front(size_type n)
187 : : {
188 [ + + ]: 64305 : if (n > static_cast<size_type>(m_pad_begin)) {
189 : 39933 : n -= m_pad_begin + 1;
190 : 39933 : m_pad_begin = BITS_PER_WORD - 1;
191 : 39933 : m_deque.insert(m_deque.begin(), 1 + (n / BITS_PER_WORD), {});
192 : 39933 : n %= BITS_PER_WORD;
193 : 39933 : }
194 : 64305 : m_pad_begin -= n;
195 : 64305 : }
196 : :
197 : : /** Insert a sequence of falses anywhere in the container. */
198 : 106426 : void insert_zeroes(size_type before, size_type count)
199 : : {
200 : 106426 : size_type after = size() - before;
201 [ + + ]: 106426 : if (before < after) {
202 : 51065 : extend_front(count);
203 : 51065 : std::move(begin() + count, begin() + count + before, begin());
204 : 51065 : } else {
205 : 55361 : extend_back(count);
206 : 55361 : std::move_backward(begin() + before, begin() + before + after, end());
207 : : }
208 : 106426 : }
209 : :
210 : : public:
211 : : /** Construct an empty container. */
212 : 41037 : explicit bitdeque() : m_pad_begin{0}, m_pad_end{0} {}
213 : :
214 : : /** Set the container equal to count times the value of val. */
215 : 139396 : void assign(size_type count, bool val)
216 : : {
217 : 139396 : m_deque.clear();
218 : 139396 : m_deque.resize((count + BITS_PER_WORD - 1) / BITS_PER_WORD);
219 : 139396 : m_pad_begin = 0;
220 : 139396 : m_pad_end = 0;
221 [ + + ]: 139396 : if (val) {
222 [ + + ]: 657591 : for (auto& elem : m_deque) elem.flip();
223 : 23771 : }
224 [ + + ]: 139396 : if (count % BITS_PER_WORD) {
225 : 114543 : erase_back(BITS_PER_WORD - (count % BITS_PER_WORD));
226 : 114543 : }
227 : 139396 : }
228 : :
229 : : /** Construct a container containing count times the value of val. */
230 [ + - ]: 31832 : bitdeque(size_type count, bool val) { assign(count, val); }
231 : :
232 : : /** Construct a container containing count false values. */
233 [ + - ]: 5443 : explicit bitdeque(size_t count) { assign(count, false); }
234 : :
235 : : /** Copy constructor. */
236 : : bitdeque(const bitdeque&) = default;
237 : :
238 : : /** Move constructor. */
239 : : bitdeque(bitdeque&&) noexcept = default;
240 : :
241 : : /** Copy assignment operator. */
242 : 19929 : bitdeque& operator=(const bitdeque& other) = default;
243 : :
244 : : /** Move assignment operator. */
245 : 77419 : bitdeque& operator=(bitdeque&& other) noexcept = default;
246 : :
247 : : // Iterator functions.
248 [ + - ]: 746386 : iterator begin() noexcept { return {m_deque.begin(), m_pad_begin}; }
249 [ + - + - ]: 10262404 : iterator end() noexcept { return iterator{m_deque.end(), 0} - m_pad_end; }
250 [ + - ]: 194579 : const_iterator begin() const noexcept { return const_iterator{m_deque.cbegin(), m_pad_begin}; }
251 [ + - ]: 166304 : const_iterator cbegin() const noexcept { return const_iterator{m_deque.cbegin(), m_pad_begin}; }
252 [ + - + - ]: 72651 : const_iterator end() const noexcept { return const_iterator{m_deque.cend(), 0} - m_pad_end; }
253 [ + - + - ]: 60764 : const_iterator cend() const noexcept { return const_iterator{m_deque.cend(), 0} - m_pad_end; }
254 : 4597 : reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; }
255 : 4597 : reverse_iterator rend() noexcept { return reverse_iterator{begin()}; }
256 : 3943 : const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{cend()}; }
257 : 4347 : const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; }
258 : 3943 : const_reverse_iterator rend() const noexcept { return const_reverse_iterator{cbegin()}; }
259 : 4347 : const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; }
260 : :
261 : : /** Count the number of bits in the container. */
262 : 240603 : size_type size() const noexcept { return m_deque.size() * BITS_PER_WORD - m_pad_begin - m_pad_end; }
263 : :
264 : : /** Determine whether the container is empty. */
265 : 4170 : bool empty() const noexcept
266 : : {
267 [ + + + + ]: 4170 : return m_deque.size() == 0 || (m_deque.size() == 1 && (m_pad_begin + m_pad_end == BITS_PER_WORD));
268 : : }
269 : :
270 : : /** Return the maximum size of the container. */
271 : 6254 : size_type max_size() const noexcept
272 : : {
273 [ - + ]: 6254 : if (m_deque.max_size() < std::numeric_limits<difference_type>::max() / BITS_PER_WORD) {
274 : 0 : return m_deque.max_size() * BITS_PER_WORD;
275 : : } else {
276 : 6254 : return std::numeric_limits<difference_type>::max();
277 : : }
278 : 6254 : }
279 : :
280 : : /** Set the container equal to the bits in [first,last). */
281 : : template<typename It>
282 : 39838 : void assign(It first, It last)
283 : : {
284 : 39838 : size_type count = std::distance(first, last);
285 : 39838 : assign(count, false);
286 : 39838 : auto it = begin();
287 [ + + ]: 38472438 : while (first != last) {
288 : 38432600 : *(it++) = *(first++);
289 : : }
290 : 39838 : }
291 : :
292 : : /** Set the container equal to the bits in ilist. */
293 : 46348 : void assign(std::initializer_list<bool> ilist)
294 : : {
295 : 46348 : assign(ilist.size(), false);
296 : 46348 : auto it = begin();
297 : 46348 : auto init = ilist.begin();
298 [ + + ]: 211742 : while (init != ilist.end()) {
299 : 165394 : *(it++) = *(init++);
300 : : }
301 : 46348 : }
302 : :
303 : : /** Set the container equal to the bits in ilist. */
304 : 13443 : bitdeque& operator=(std::initializer_list<bool> ilist)
305 : : {
306 : 13443 : assign(ilist);
307 : 13443 : return *this;
308 : : }
309 : :
310 : : /** Construct a container containing the bits in [first,last). */
311 : : template<typename It>
312 [ + - ]: 24122 : bitdeque(It first, It last) { assign(first, last); }
313 : :
314 : : /** Construct a container containing the bits in ilist. */
315 [ + - ]: 13175 : bitdeque(std::initializer_list<bool> ilist) { assign(ilist); }
316 : :
317 : : // Access an element of the container, with bounds checking.
318 : 25018 : reference at(size_type position)
319 : : {
320 [ + + + - ]: 25018 : if (position >= size()) throw std::out_of_range("bitdeque::at() out of range");
321 : 12944 : return begin()[position];
322 : 0 : }
323 : 3402 : const_reference at(size_type position) const
324 : : {
325 [ + + + - ]: 3402 : if (position >= size()) throw std::out_of_range("bitdeque::at() out of range");
326 : 1693 : return cbegin()[position];
327 : 0 : }
328 : :
329 : : // Access elements of the container without bounds checking.
330 : 33870 : reference operator[](size_type position) { return begin()[position]; }
331 : : const_reference operator[](size_type position) const { return cbegin()[position]; }
332 : 19997 : reference front() { return *begin(); }
333 : 2070 : const_reference front() const { return *cbegin(); }
334 : 10080178 : reference back() { return end()[-1]; }
335 : 4649 : const_reference back() const { return cend()[-1]; }
336 : :
337 : : /** Release unused memory. */
338 : : void shrink_to_fit()
339 : : {
340 : : m_deque.shrink_to_fit();
341 : : }
342 : :
343 : : /** Empty the container. */
344 : 8479 : void clear() noexcept
345 : : {
346 : 8479 : m_deque.clear();
347 : 8479 : m_pad_begin = m_pad_end = 0;
348 : 8479 : }
349 : :
350 : : // Append an element to the container.
351 : 10073777 : void push_back(bool val)
352 : : {
353 : 10073777 : extend_back(1);
354 : 10073777 : back() = val;
355 : 10073777 : }
356 : : reference emplace_back(bool val)
357 : : {
358 : : extend_back(1);
359 : : auto ref = back();
360 : : ref = val;
361 : : return ref;
362 : : }
363 : :
364 : : // Prepend an element to the container.
365 : 13240 : void push_front(bool val)
366 : : {
367 : 13240 : extend_front(1);
368 : 13240 : front() = val;
369 : 13240 : }
370 : : reference emplace_front(bool val)
371 : : {
372 : : extend_front(1);
373 : : auto ref = front();
374 : : ref = val;
375 : : return ref;
376 : : }
377 : :
378 : : // Remove the last element from the container.
379 : 6221 : void pop_back()
380 : : {
381 : 6221 : erase_back(1);
382 : 6221 : }
383 : :
384 : : // Remove the first element from the container.
385 : 5138 : void pop_front()
386 : : {
387 : 5138 : erase_front(1);
388 : 5138 : }
389 : :
390 : : /** Resize the container. */
391 : 13282 : void resize(size_type n)
392 : : {
393 [ + + ]: 13282 : if (n < size()) {
394 : 3697 : erase_back(size() - n);
395 : 3697 : } else {
396 : 9585 : extend_back(n - size());
397 : : }
398 : 13282 : }
399 : :
400 : : // Swap two containers.
401 : 16445 : void swap(bitdeque& other) noexcept
402 : : {
403 : 16445 : std::swap(m_deque, other.m_deque);
404 : 16445 : std::swap(m_pad_begin, other.m_pad_begin);
405 : 16445 : std::swap(m_pad_end, other.m_pad_end);
406 : 16445 : }
407 : 6179 : friend void swap(bitdeque& b1, bitdeque& b2) noexcept { b1.swap(b2); }
408 : :
409 : : // Erase elements from the container.
410 : 45100 : iterator erase(const_iterator first, const_iterator last)
411 : : {
412 : 45100 : size_type before = std::distance(cbegin(), first);
413 : 45100 : size_type dist = std::distance(first, last);
414 : 45100 : size_type after = std::distance(last, cend());
415 [ + + ]: 45100 : if (before < after) {
416 : 22809 : std::move_backward(begin(), begin() + before, end() - after);
417 : 22809 : erase_front(dist);
418 : 22809 : return begin() + before;
419 : : } else {
420 : 22291 : std::move(end() - after, end(), begin() + before);
421 : 22291 : erase_back(dist);
422 : 22291 : return end() - after;
423 : : }
424 : 45100 : }
425 : :
426 : : iterator erase(iterator first, iterator last) { return erase(const_iterator{first}, const_iterator{last}); }
427 : 10410 : iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
428 : : iterator erase(iterator pos) { return erase(const_iterator{pos}, const_iterator{pos} + 1); }
429 : :
430 : : // Insert elements into the container.
431 : 17627 : iterator insert(const_iterator pos, bool val)
432 : : {
433 : 17627 : size_type before = pos - cbegin();
434 : 17627 : insert_zeroes(before, 1);
435 : 17627 : auto it = begin() + before;
436 : 17627 : *it = val;
437 : : return it;
438 : 17627 : }
439 : :
440 : 13108 : iterator emplace(const_iterator pos, bool val) { return insert(pos, val); }
441 : :
442 : 38560 : iterator insert(const_iterator pos, size_type count, bool val)
443 : : {
444 : 38560 : size_type before = pos - cbegin();
445 : 38560 : insert_zeroes(before, count);
446 : 38560 : auto it_begin = begin() + before;
447 : 38560 : auto it = it_begin;
448 : 38560 : auto it_end = it + count;
449 [ + + ]: 52847337 : while (it != it_end) *(it++) = val;
450 : : return it_begin;
451 : 38560 : }
452 : :
453 : : template<typename It>
454 : 50239 : iterator insert(const_iterator pos, It first, It last)
455 : : {
456 : 50239 : size_type before = pos - cbegin();
457 : 50239 : size_type count = std::distance(first, last);
458 : 50239 : insert_zeroes(before, count);
459 : 50239 : auto it_begin = begin() + before;
460 : 50239 : auto it = it_begin;
461 [ + + ]: 90630520 : while (first != last) {
462 : 90580281 : *(it++) = *(first++);
463 : : }
464 : : return it_begin;
465 : 50239 : }
466 : : };
467 : :
468 : : #endif // BITCOIN_UTIL_BITDEQUE_H
|