Bitcoin ABC 0.30.5
P2P Digital Currency
bitdeque.h
Go to the documentation of this file.
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
22template <int BlobSize = 4096 * 8> class bitdeque {
23 // Internal definitions
24 using word_type = std::bitset<BlobSize>;
25 using deque_type = std::deque<word_type>;
26 static_assert(BlobSize > 0);
27 static constexpr int BITS_PER_WORD = BlobSize;
28
29 // Forward and friend declarations of iterator types.
30 template <bool Const> class Iterator;
31 template <bool Const> friend class Iterator;
32
34 template <bool Const> class Iterator {
36 std::conditional_t<Const, typename deque_type::const_iterator,
37 typename deque_type::iterator>;
38
40 int m_bitpos{0};
41 Iterator(const deque_iterator &it, int bitpos)
42 : m_it(it), m_bitpos(bitpos) {}
43 friend class bitdeque;
44
45 public:
46 using iterator_category = std::random_access_iterator_tag;
47 using value_type = bool;
48 using pointer = void;
49 using const_pointer = void;
50 using reference =
51 std::conditional_t<Const, bool, typename word_type::reference>;
52 using const_reference = bool;
53 using difference_type = std::ptrdiff_t;
54
56 Iterator() = default;
57
59 Iterator(const Iterator &) = default;
60
62 template <bool ConstArg = Const,
63 typename = std::enable_if_t<Const && ConstArg>>
65 : m_it(x.m_it), m_bitpos(x.m_bitpos) {}
66
68 if (dist > 0) {
69 if (dist + m_bitpos >= BITS_PER_WORD) {
70 ++m_it;
71 dist -= BITS_PER_WORD - m_bitpos;
72 m_bitpos = 0;
73 }
74 auto jump = dist / BITS_PER_WORD;
75 m_it += jump;
76 m_bitpos += dist - jump * BITS_PER_WORD;
77 } else if (dist < 0) {
78 dist = -dist;
79 if (dist > m_bitpos) {
80 --m_it;
81 dist -= m_bitpos + 1;
83 }
84 auto jump = dist / BITS_PER_WORD;
85 m_it -= jump;
86 m_bitpos -= dist - jump * BITS_PER_WORD;
87 }
88 return *this;
89 }
90
91 friend difference_type operator-(const Iterator &x, const Iterator &y) {
92 return BITS_PER_WORD * (x.m_it - y.m_it) + x.m_bitpos - y.m_bitpos;
93 }
94
95 Iterator &operator=(const Iterator &) = default;
98 ++m_bitpos;
99 if (m_bitpos == BITS_PER_WORD) {
100 m_bitpos = 0;
101 ++m_it;
102 };
103 return *this;
104 }
106 auto ret{*this};
107 operator++();
108 return ret;
109 }
111 if (m_bitpos == 0) {
113 --m_it;
114 };
115 --m_bitpos;
116 return *this;
117 }
119 auto ret{*this};
120 operator--();
121 return ret;
122 }
124 x += dist;
125 return x;
126 }
128 x += dist;
129 return x;
130 }
132 x -= dist;
133 return x;
134 }
135 friend bool operator<(const Iterator &x, const Iterator &y) {
136 return std::tie(x.m_it, x.m_bitpos) < std::tie(y.m_it, y.m_bitpos);
137 }
138 friend bool operator>(const Iterator &x, const Iterator &y) {
139 return std::tie(x.m_it, x.m_bitpos) > std::tie(y.m_it, y.m_bitpos);
140 }
141 friend bool operator<=(const Iterator &x, const Iterator &y) {
142 return std::tie(x.m_it, x.m_bitpos) <= std::tie(y.m_it, y.m_bitpos);
143 }
144 friend bool operator>=(const Iterator &x, const Iterator &y) {
145 return std::tie(x.m_it, x.m_bitpos) >= std::tie(y.m_it, y.m_bitpos);
146 }
147 friend bool operator==(const Iterator &x, const Iterator &y) {
148 return x.m_it == y.m_it && x.m_bitpos == y.m_bitpos;
149 }
150 friend bool operator!=(const Iterator &x, const Iterator &y) {
151 return x.m_it != y.m_it || x.m_bitpos != y.m_bitpos;
152 }
153 reference operator*() const { return (*m_it)[m_bitpos]; }
155 return *(*this + pos);
156 }
157 };
158
159public:
160 using value_type = bool;
161 using size_type = std::size_t;
162 using difference_type = typename deque_type::difference_type;
163 using reference = typename word_type::reference;
164 using const_reference = bool;
167 using pointer = void;
168 using const_pointer = void;
169 using reverse_iterator = std::reverse_iterator<iterator>;
170 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
171
172private:
175
178
181
184 if (n >= static_cast<size_type>(BITS_PER_WORD - m_pad_end)) {
186 m_pad_end = 0;
187 m_deque.erase(m_deque.end() - 1 - (n / BITS_PER_WORD),
188 m_deque.end());
189 n %= BITS_PER_WORD;
190 }
191 if (n) {
192 auto &last = m_deque.back();
193 while (n) {
194 last.reset(BITS_PER_WORD - 1 - m_pad_end);
195 ++m_pad_end;
196 --n;
197 }
198 }
199 }
200
203 if (n > static_cast<size_type>(m_pad_end)) {
204 n -= m_pad_end + 1;
206 m_deque.insert(m_deque.end(), 1 + (n / BITS_PER_WORD), {});
207 n %= BITS_PER_WORD;
208 }
209 m_pad_end -= n;
210 }
211
214 if (n >= static_cast<size_type>(BITS_PER_WORD - m_pad_begin)) {
216 m_pad_begin = 0;
217 m_deque.erase(m_deque.begin(),
218 m_deque.begin() + 1 + (n / BITS_PER_WORD));
219 n %= BITS_PER_WORD;
220 }
221 if (n) {
222 auto &first = m_deque.front();
223 while (n) {
224 first.reset(m_pad_begin);
225 ++m_pad_begin;
226 --n;
227 }
228 }
229 }
230
233 if (n > static_cast<size_type>(m_pad_begin)) {
234 n -= m_pad_begin + 1;
236 m_deque.insert(m_deque.begin(), 1 + (n / BITS_PER_WORD), {});
237 n %= BITS_PER_WORD;
238 }
239 m_pad_begin -= n;
240 }
241
244 size_type after = size() - before;
245 if (before < after) {
247 std::move(begin() + count, begin() + count + before, begin());
248 } else {
250 std::move_backward(begin() + before, begin() + before + after,
251 end());
252 }
253 }
254
255public:
257 explicit bitdeque() : m_pad_begin{0}, m_pad_end{0} {}
258
260 void assign(size_type count, bool val) {
261 m_deque.clear();
262 m_deque.resize((count + BITS_PER_WORD - 1) / BITS_PER_WORD);
263 m_pad_begin = 0;
264 m_pad_end = 0;
265 if (val) {
266 for (auto &elem : m_deque)
267 elem.flip();
268 }
269 if (count % BITS_PER_WORD) {
271 }
272 }
273
275 bitdeque(size_type count, bool val) { assign(count, val); }
276
278 explicit bitdeque(size_t count) { assign(count, false); }
279
281 bitdeque(const bitdeque &) = default;
282
284 bitdeque(bitdeque &&) noexcept = default;
285
287 bitdeque &operator=(const bitdeque &other) = default;
288
290 bitdeque &operator=(bitdeque &&other) noexcept = default;
291
292 // Iterator functions.
293 iterator begin() noexcept { return {m_deque.begin(), m_pad_begin}; }
294 iterator end() noexcept { return iterator{m_deque.end(), 0} - m_pad_end; }
295 const_iterator begin() const noexcept {
296 return const_iterator{m_deque.cbegin(), m_pad_begin};
297 }
298 const_iterator cbegin() const noexcept {
299 return const_iterator{m_deque.cbegin(), m_pad_begin};
300 }
301 const_iterator end() const noexcept {
302 return const_iterator{m_deque.cend(), 0} - m_pad_end;
303 }
304 const_iterator cend() const noexcept {
305 return const_iterator{m_deque.cend(), 0} - m_pad_end;
306 }
307 reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; }
308 reverse_iterator rend() noexcept { return reverse_iterator{begin()}; }
311 }
314 }
315 const_reverse_iterator rend() const noexcept {
317 }
318 const_reverse_iterator crend() const noexcept {
320 }
321
323 size_type size() const noexcept {
324 return m_deque.size() * BITS_PER_WORD - m_pad_begin - m_pad_end;
325 }
326
328 bool empty() const noexcept {
329 return m_deque.size() == 0 ||
330 (m_deque.size() == 1 &&
332 }
333
335 size_type max_size() const noexcept {
336 if (m_deque.max_size() <
337 std::numeric_limits<difference_type>::max() / BITS_PER_WORD) {
338 return m_deque.max_size() * BITS_PER_WORD;
339 } else {
340 return std::numeric_limits<difference_type>::max();
341 }
342 }
343
345 template <typename It> void assign(It first, It last) {
346 size_type count = std::distance(first, last);
347 assign(count, false);
348 auto it = begin();
349 while (first != last) {
350 *(it++) = *(first++);
351 }
352 }
353
355 void assign(std::initializer_list<bool> ilist) {
356 assign(ilist.size(), false);
357 auto it = begin();
358 auto init = ilist.begin();
359 while (init != ilist.end()) {
360 *(it++) = *(init++);
361 }
362 }
363
365 bitdeque &operator=(std::initializer_list<bool> ilist) {
366 assign(ilist);
367 return *this;
368 }
369
371 template <typename It> bitdeque(It first, It last) { assign(first, last); }
372
374 bitdeque(std::initializer_list<bool> ilist) { assign(ilist); }
375
376 // Access an element of the container, with bounds checking.
378 if (position >= size())
379 throw std::out_of_range("bitdeque::at() out of range");
380 return begin()[position];
381 }
382 const_reference at(size_type position) const {
383 if (position >= size())
384 throw std::out_of_range("bitdeque::at() out of range");
385 return cbegin()[position];
386 }
387
388 // Access elements of the container without bounds checking.
389 reference operator[](size_type position) { return begin()[position]; }
391 return cbegin()[position];
392 }
393 reference front() { return *begin(); }
394 const_reference front() const { return *cbegin(); }
395 reference back() { return end()[-1]; }
396 const_reference back() const { return cend()[-1]; }
397
399 void shrink_to_fit() { m_deque.shrink_to_fit(); }
400
402 void clear() noexcept {
403 m_deque.clear();
405 }
406
407 // Append an element to the container.
408 void push_back(bool val) {
409 extend_back(1);
410 back() = val;
411 }
413 extend_back(1);
414 auto ref = back();
415 ref = val;
416 return ref;
417 }
418
419 // Prepend an element to the container.
420 void push_front(bool val) {
421 extend_front(1);
422 front() = val;
423 }
425 extend_front(1);
426 auto ref = front();
427 ref = val;
428 return ref;
429 }
430
431 // Remove the last element from the container.
432 void pop_back() { erase_back(1); }
433
434 // Remove the first element from the container.
435 void pop_front() { erase_front(1); }
436
439 if (n < size()) {
440 erase_back(size() - n);
441 } else {
442 extend_back(n - size());
443 }
444 }
445
446 // Swap two containers.
447 void swap(bitdeque &other) noexcept {
448 std::swap(m_deque, other.m_deque);
449 std::swap(m_pad_begin, other.m_pad_begin);
450 std::swap(m_pad_end, other.m_pad_end);
451 }
452 friend void swap(bitdeque &b1, bitdeque &b2) noexcept { b1.swap(b2); }
453
454 // Erase elements from the container.
456 size_type before = std::distance(cbegin(), first);
457 size_type dist = std::distance(first, last);
458 size_type after = std::distance(last, cend());
459 if (before < after) {
460 std::move_backward(begin(), begin() + before, end() - after);
461 erase_front(dist);
462 return begin() + before;
463 } else {
464 std::move(end() - after, end(), begin() + before);
465 erase_back(dist);
466 return end() - after;
467 }
468 }
469
471 return erase(const_iterator{first}, const_iterator{last});
472 }
473 iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
475 return erase(const_iterator{pos}, const_iterator{pos} + 1);
476 }
477
478 // Insert elements into the container.
480 size_type before = pos - cbegin();
481 insert_zeroes(before, 1);
482 auto it = begin() + before;
483 *it = val;
484 return it;
485 }
486
487 iterator emplace(const_iterator pos, bool val) { return insert(pos, val); }
488
490 size_type before = pos - cbegin();
491 insert_zeroes(before, count);
492 auto it_begin = begin() + before;
493 auto it = it_begin;
494 auto it_end = it + count;
495 while (it != it_end)
496 *(it++) = val;
497 return it_begin;
498 }
499
500 template <typename It>
501 iterator insert(const_iterator pos, It first, It last) {
502 size_type before = pos - cbegin();
503 size_type count = std::distance(first, last);
504 insert_zeroes(before, count);
505 auto it_begin = begin() + before;
506 auto it = it_begin;
507 while (first != last) {
508 *(it++) = *(first++);
509 }
510 return it_begin;
511 }
512};
513
514#endif // BITCOIN_UTIL_BITDEQUE_H
Iterator to a bitdeque element, const or not.
Definition: bitdeque.h:34
friend bool operator!=(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:150
Iterator & operator--()
Definition: bitdeque.h:110
Iterator operator--(int)
Definition: bitdeque.h:118
deque_iterator m_it
Definition: bitdeque.h:39
Iterator(const deque_iterator &it, int bitpos)
Definition: bitdeque.h:41
Iterator & operator+=(difference_type dist)
Definition: bitdeque.h:67
bool const_reference
Definition: bitdeque.h:52
friend bool operator==(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:147
reference operator*() const
Definition: bitdeque.h:153
Iterator(const Iterator< false > &x)
Conversion from non-const to const iterator.
Definition: bitdeque.h:64
Iterator & operator-=(difference_type dist)
Definition: bitdeque.h:96
Iterator & operator++()
Definition: bitdeque.h:97
Iterator()=default
Default constructor.
std::random_access_iterator_tag iterator_category
Definition: bitdeque.h:46
Iterator & operator=(const Iterator &)=default
friend Iterator operator-(Iterator x, difference_type dist)
Definition: bitdeque.h:131
friend Iterator operator+(Iterator x, difference_type dist)
Definition: bitdeque.h:123
Iterator(const Iterator &)=default
Default copy constructor.
std::conditional_t< Const, bool, typename word_type::reference > reference
Definition: bitdeque.h:51
friend bool operator>=(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:144
friend difference_type operator-(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:91
Iterator operator++(int)
Definition: bitdeque.h:105
std::ptrdiff_t difference_type
Definition: bitdeque.h:53
std::conditional_t< Const, typename deque_type::const_iterator, typename deque_type::iterator > deque_iterator
Definition: bitdeque.h:37
friend bool operator>(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:138
reference operator[](difference_type pos) const
Definition: bitdeque.h:154
friend bool operator<=(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:141
friend Iterator operator+(difference_type dist, Iterator x)
Definition: bitdeque.h:127
friend bool operator<(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:135
Class that mimics std::deque<bool>, but with std::vector<bool>'s bit packing.
Definition: bitdeque.h:22
bool const_reference
Definition: bitdeque.h:164
bitdeque & operator=(std::initializer_list< bool > ilist)
Set the container equal to the bits in ilist.
Definition: bitdeque.h:365
iterator erase(iterator first, iterator last)
Definition: bitdeque.h:470
const_reference operator[](size_type position) const
Definition: bitdeque.h:390
bitdeque(size_t count)
Construct a container containing count false values.
Definition: bitdeque.h:278
std::size_t size_type
Definition: bitdeque.h:161
iterator insert(const_iterator pos, bool val)
Definition: bitdeque.h:479
void push_front(bool val)
Definition: bitdeque.h:420
void push_back(bool val)
Definition: bitdeque.h:408
typename deque_type::difference_type difference_type
Definition: bitdeque.h:162
const_reverse_iterator crend() const noexcept
Definition: bitdeque.h:318
void assign(It first, It last)
Set the container equal to the bits in [first,last).
Definition: bitdeque.h:345
std::deque< word_type > deque_type
Definition: bitdeque.h:25
iterator erase(iterator pos)
Definition: bitdeque.h:474
iterator begin() noexcept
Definition: bitdeque.h:293
void erase_front(size_type n)
Shrink the container by n bits, removing from the beginning.
Definition: bitdeque.h:213
bitdeque(const bitdeque &)=default
Copy constructor.
reference front()
Definition: bitdeque.h:393
const_reverse_iterator rbegin() const noexcept
Definition: bitdeque.h:309
iterator emplace(const_iterator pos, bool val)
Definition: bitdeque.h:487
int m_pad_end
Number of unused bits at the back of m_deque.back().
Definition: bitdeque.h:180
void pop_front()
Definition: bitdeque.h:435
iterator insert(const_iterator pos, It first, It last)
Definition: bitdeque.h:501
const_reference front() const
Definition: bitdeque.h:394
const_iterator end() const noexcept
Definition: bitdeque.h:301
bitdeque(std::initializer_list< bool > ilist)
Construct a container containing the bits in ilist.
Definition: bitdeque.h:374
friend void swap(bitdeque &b1, bitdeque &b2) noexcept
Definition: bitdeque.h:452
iterator erase(const_iterator first, const_iterator last)
Definition: bitdeque.h:455
deque_type m_deque
Deque of bitsets storing the actual bit data.
Definition: bitdeque.h:174
const_iterator cend() const noexcept
Definition: bitdeque.h:304
std::bitset< BlobSize > word_type
Definition: bitdeque.h:24
reverse_iterator rend() noexcept
Definition: bitdeque.h:308
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: bitdeque.h:170
bitdeque(bitdeque &&) noexcept=default
Move constructor.
const_reverse_iterator rend() const noexcept
Definition: bitdeque.h:315
reference emplace_front(bool val)
Definition: bitdeque.h:424
reference back()
Definition: bitdeque.h:395
const_reverse_iterator crbegin() const noexcept
Definition: bitdeque.h:312
void assign(size_type count, bool val)
Set the container equal to count times the value of val.
Definition: bitdeque.h:260
reference emplace_back(bool val)
Definition: bitdeque.h:412
bitdeque(size_type count, bool val)
Construct a container containing count times the value of val.
Definition: bitdeque.h:275
size_type max_size() const noexcept
Return the maximum size of the container.
Definition: bitdeque.h:335
void pop_back()
Definition: bitdeque.h:432
const_reference back() const
Definition: bitdeque.h:396
void pointer
Definition: bitdeque.h:167
bitdeque(It first, It last)
Construct a container containing the bits in [first,last).
Definition: bitdeque.h:371
size_type size() const noexcept
Count the number of bits in the container.
Definition: bitdeque.h:323
void resize(size_type n)
Resize the container.
Definition: bitdeque.h:438
bool value_type
Definition: bitdeque.h:160
int m_pad_begin
Number of unused bits at the front of m_deque.front().
Definition: bitdeque.h:177
typename word_type::reference reference
Definition: bitdeque.h:163
bool empty() const noexcept
Determine whether the container is empty.
Definition: bitdeque.h:328
iterator erase(const_iterator pos)
Definition: bitdeque.h:473
iterator end() noexcept
Definition: bitdeque.h:294
void extend_front(size_type n)
Extend the container by n bits, adding at the beginning.
Definition: bitdeque.h:232
void insert_zeroes(size_type before, size_type count)
Insert a sequence of falses anywhere in the container.
Definition: bitdeque.h:243
iterator insert(const_iterator pos, size_type count, bool val)
Definition: bitdeque.h:489
const_iterator cbegin() const noexcept
Definition: bitdeque.h:298
std::reverse_iterator< iterator > reverse_iterator
Definition: bitdeque.h:169
const_iterator begin() const noexcept
Definition: bitdeque.h:295
static constexpr int BITS_PER_WORD
Definition: bitdeque.h:27
reference operator[](size_type position)
Definition: bitdeque.h:389
void const_pointer
Definition: bitdeque.h:168
reference at(size_type position)
Definition: bitdeque.h:377
void swap(bitdeque &other) noexcept
Definition: bitdeque.h:447
const_reference at(size_type position) const
Definition: bitdeque.h:382
void assign(std::initializer_list< bool > ilist)
Set the container equal to the bits in ilist.
Definition: bitdeque.h:355
void extend_back(size_type n)
Extend the container by n bits, adding at the end.
Definition: bitdeque.h:202
void clear() noexcept
Empty the container.
Definition: bitdeque.h:402
void erase_back(size_type n)
Shrink the container by n bits, removing from the end.
Definition: bitdeque.h:183
bitdeque()
Construct an empty container.
Definition: bitdeque.h:257
reverse_iterator rbegin() noexcept
Definition: bitdeque.h:307
void shrink_to_fit()
Release unused memory.
Definition: bitdeque.h:399
Definition: common.cpp:29
bool Const(const std::string &str, Span< const char > &sp)
Parse a constant.
Definition: spanparsing.cpp:14
static int count
Definition: tests.c:31