Bitcoin Core 30.99.0
P2P Digital Currency
bitdeque.h
Go to the documentation of this file.
1// Copyright (c) 2022-present 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
21template<int BITS_PER_WORD = 4096 * 8>
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
34 template<bool Const>
36 {
37 using deque_iterator = std::conditional_t<Const, typename deque_type::const_iterator, typename deque_type::iterator>;
38
40 int m_bitpos{0};
41 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
54 Iterator() = default;
55
57 Iterator(const Iterator&) = default;
58
60 template<bool ConstArg = Const, typename = std::enable_if_t<Const && ConstArg>>
62
64 {
65 if (dist > 0) {
66 if (dist + m_bitpos >= BITS_PER_WORD) {
67 ++m_it;
68 dist -= BITS_PER_WORD - m_bitpos;
69 m_bitpos = 0;
70 }
71 auto jump = dist / BITS_PER_WORD;
72 m_it += jump;
73 m_bitpos += dist - jump * BITS_PER_WORD;
74 } else if (dist < 0) {
75 dist = -dist;
76 if (dist > m_bitpos) {
77 --m_it;
78 dist -= m_bitpos + 1;
79 m_bitpos = BITS_PER_WORD - 1;
80 }
81 auto jump = dist / BITS_PER_WORD;
82 m_it -= jump;
83 m_bitpos -= dist - jump * BITS_PER_WORD;
84 }
85 return *this;
86 }
87
88 friend difference_type operator-(const Iterator& x, const Iterator& y)
89 {
90 return BITS_PER_WORD * (x.m_it - y.m_it) + x.m_bitpos - y.m_bitpos;
91 }
92
93 Iterator& operator=(const Iterator&) = default;
95 Iterator& operator++() { ++m_bitpos; if (m_bitpos == BITS_PER_WORD) { m_bitpos = 0; ++m_it; }; return *this; }
96 Iterator operator++(int) { auto ret{*this}; operator++(); return ret; }
97 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 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 friend Iterator operator-(Iterator x, difference_type dist) { x -= dist; return x; }
102 friend auto 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 x.m_it == y.m_it && x.m_bitpos == y.m_bitpos; }
104 reference operator*() const { return (*m_it)[m_bitpos]; }
105 reference operator[](difference_type pos) const { return *(*this + pos); }
106 };
107
108public:
109 using value_type = bool;
110 using size_type = std::size_t;
111 using difference_type = typename deque_type::difference_type;
112 using reference = typename word_type::reference;
113 using const_reference = bool;
116 using pointer = void;
117 using const_pointer = void;
118 using reverse_iterator = std::reverse_iterator<iterator>;
119 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
120
121private:
124
127
130
133 {
134 if (n >= static_cast<size_type>(BITS_PER_WORD - m_pad_end)) {
135 n -= BITS_PER_WORD - m_pad_end;
136 m_pad_end = 0;
137 m_deque.erase(m_deque.end() - 1 - (n / BITS_PER_WORD), m_deque.end());
138 n %= BITS_PER_WORD;
139 }
140 if (n) {
141 auto& last = m_deque.back();
142 while (n) {
143 last.reset(BITS_PER_WORD - 1 - m_pad_end);
144 ++m_pad_end;
145 --n;
146 }
147 }
148 }
149
152 {
153 if (n > static_cast<size_type>(m_pad_end)) {
154 n -= m_pad_end + 1;
155 m_pad_end = BITS_PER_WORD - 1;
156 m_deque.insert(m_deque.end(), 1 + (n / BITS_PER_WORD), {});
157 n %= BITS_PER_WORD;
158 }
159 m_pad_end -= n;
160 }
161
164 {
165 if (n >= static_cast<size_type>(BITS_PER_WORD - m_pad_begin)) {
166 n -= BITS_PER_WORD - m_pad_begin;
167 m_pad_begin = 0;
168 m_deque.erase(m_deque.begin(), m_deque.begin() + 1 + (n / BITS_PER_WORD));
169 n %= BITS_PER_WORD;
170 }
171 if (n) {
172 auto& first = m_deque.front();
173 while (n) {
174 first.reset(m_pad_begin);
175 ++m_pad_begin;
176 --n;
177 }
178 }
179 }
180
183 {
184 if (n > static_cast<size_type>(m_pad_begin)) {
185 n -= m_pad_begin + 1;
186 m_pad_begin = BITS_PER_WORD - 1;
187 m_deque.insert(m_deque.begin(), 1 + (n / BITS_PER_WORD), {});
188 n %= BITS_PER_WORD;
189 }
190 m_pad_begin -= n;
191 }
192
195 {
196 size_type after = size() - before;
197 if (before < after) {
199 std::move(begin() + count, begin() + count + before, begin());
200 } else {
202 std::move_backward(begin() + before, begin() + before + after, end());
203 }
204 }
205
206public:
208 explicit bitdeque() : m_pad_begin{0}, m_pad_end{0} {}
209
211 void assign(size_type count, bool val)
212 {
213 m_deque.clear();
214 m_deque.resize((count + BITS_PER_WORD - 1) / BITS_PER_WORD);
215 m_pad_begin = 0;
216 m_pad_end = 0;
217 if (val) {
218 for (auto& elem : m_deque) elem.flip();
219 }
220 if (count % BITS_PER_WORD) {
221 erase_back(BITS_PER_WORD - (count % BITS_PER_WORD));
222 }
223 }
224
226 bitdeque(size_type count, bool val) { assign(count, val); }
227
229 explicit bitdeque(size_t count) { assign(count, false); }
230
232 bitdeque(const bitdeque&) = default;
233
235 bitdeque(bitdeque&&) noexcept = default;
236
238 bitdeque& operator=(const bitdeque& other) = default;
239
241 bitdeque& operator=(bitdeque&& other) noexcept = default;
242
243 // Iterator functions.
244 iterator begin() noexcept { return {m_deque.begin(), m_pad_begin}; }
245 iterator end() noexcept { return iterator{m_deque.end(), 0} - m_pad_end; }
246 const_iterator begin() const noexcept { return const_iterator{m_deque.cbegin(), m_pad_begin}; }
247 const_iterator cbegin() const noexcept { return const_iterator{m_deque.cbegin(), m_pad_begin}; }
248 const_iterator end() const noexcept { return const_iterator{m_deque.cend(), 0} - m_pad_end; }
249 const_iterator cend() const noexcept { return const_iterator{m_deque.cend(), 0} - m_pad_end; }
250 reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; }
251 reverse_iterator rend() noexcept { return reverse_iterator{begin()}; }
256
258 size_type size() const noexcept { return m_deque.size() * BITS_PER_WORD - m_pad_begin - m_pad_end; }
259
261 bool empty() const noexcept
262 {
263 return m_deque.size() == 0 || (m_deque.size() == 1 && (m_pad_begin + m_pad_end == BITS_PER_WORD));
264 }
265
267 size_type max_size() const noexcept
268 {
269 if (m_deque.max_size() < std::numeric_limits<difference_type>::max() / BITS_PER_WORD) {
270 return m_deque.max_size() * BITS_PER_WORD;
271 } else {
272 return std::numeric_limits<difference_type>::max();
273 }
274 }
275
277 template<typename It>
278 void assign(It first, It last)
279 {
280 size_type count = std::distance(first, last);
281 assign(count, false);
282 auto it = begin();
283 while (first != last) {
284 *(it++) = *(first++);
285 }
286 }
287
289 void assign(std::initializer_list<bool> ilist)
290 {
291 assign(ilist.size(), false);
292 auto it = begin();
293 auto init = ilist.begin();
294 while (init != ilist.end()) {
295 *(it++) = *(init++);
296 }
297 }
298
300 bitdeque& operator=(std::initializer_list<bool> ilist)
301 {
302 assign(ilist);
303 return *this;
304 }
305
307 template<typename It>
308 bitdeque(It first, It last) { assign(first, last); }
309
311 bitdeque(std::initializer_list<bool> ilist) { assign(ilist); }
312
313 // Access an element of the container, with bounds checking.
315 {
316 if (position >= size()) throw std::out_of_range("bitdeque::at() out of range");
317 return begin()[position];
318 }
320 {
321 if (position >= size()) throw std::out_of_range("bitdeque::at() out of range");
322 return cbegin()[position];
323 }
324
325 // Access elements of the container without bounds checking.
326 reference operator[](size_type position) { return begin()[position]; }
327 const_reference operator[](size_type position) const { return cbegin()[position]; }
328 reference front() { return *begin(); }
329 const_reference front() const { return *cbegin(); }
330 reference back() { return end()[-1]; }
331 const_reference back() const { return cend()[-1]; }
332
335 {
336 m_deque.shrink_to_fit();
337 }
338
340 void clear() noexcept
341 {
342 m_deque.clear();
344 }
345
346 // Append an element to the container.
347 void push_back(bool val)
348 {
349 extend_back(1);
350 back() = val;
351 }
353 {
354 extend_back(1);
355 auto ref = back();
356 ref = val;
357 return ref;
358 }
359
360 // Prepend an element to the container.
361 void push_front(bool val)
362 {
363 extend_front(1);
364 front() = val;
365 }
367 {
368 extend_front(1);
369 auto ref = front();
370 ref = val;
371 return ref;
372 }
373
374 // Remove the last element from the container.
375 void pop_back()
376 {
377 erase_back(1);
378 }
379
380 // Remove the first element from the container.
382 {
383 erase_front(1);
384 }
385
388 {
389 if (n < size()) {
390 erase_back(size() - n);
391 } else {
392 extend_back(n - size());
393 }
394 }
395
396 // Swap two containers.
397 void swap(bitdeque& other) noexcept
398 {
399 std::swap(m_deque, other.m_deque);
400 std::swap(m_pad_begin, other.m_pad_begin);
401 std::swap(m_pad_end, other.m_pad_end);
402 }
403 friend void swap(bitdeque& b1, bitdeque& b2) noexcept { b1.swap(b2); }
404
405 // Erase elements from the container.
407 {
408 size_type before = std::distance(cbegin(), first);
409 size_type dist = std::distance(first, last);
410 size_type after = std::distance(last, cend());
411 if (before < after) {
412 std::move_backward(begin(), begin() + before, end() - after);
413 erase_front(dist);
414 return begin() + before;
415 } else {
416 std::move(end() - after, end(), begin() + before);
417 erase_back(dist);
418 return end() - after;
419 }
420 }
421
422 iterator erase(iterator first, iterator last) { return erase(const_iterator{first}, const_iterator{last}); }
423 iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
424 iterator erase(iterator pos) { return erase(const_iterator{pos}, const_iterator{pos} + 1); }
425
426 // Insert elements into the container.
428 {
429 size_type before = pos - cbegin();
430 insert_zeroes(before, 1);
431 auto it = begin() + before;
432 *it = val;
433 return it;
434 }
435
436 iterator emplace(const_iterator pos, bool val) { return insert(pos, val); }
437
439 {
440 size_type before = pos - cbegin();
441 insert_zeroes(before, count);
442 auto it_begin = begin() + before;
443 auto it = it_begin;
444 auto it_end = it + count;
445 while (it != it_end) *(it++) = val;
446 return it_begin;
447 }
448
449 template<typename It>
450 iterator insert(const_iterator pos, It first, It last)
451 {
452 size_type before = pos - cbegin();
453 size_type count = std::distance(first, last);
454 insert_zeroes(before, count);
455 auto it_begin = begin() + before;
456 auto it = it_begin;
457 while (first != last) {
458 *(it++) = *(first++);
459 }
460 return it_begin;
461 }
462};
463
464#endif // BITCOIN_UTIL_BITDEQUE_H
int ret
Iterator to a bitdeque element, const or not.
Definition: bitdeque.h:36
std::ptrdiff_t difference_type
Definition: bitdeque.h:51
std::conditional_t< Const, typename deque_type::const_iterator, typename deque_type::iterator > deque_iterator
Definition: bitdeque.h:37
Iterator()=default
Default constructor.
Iterator & operator=(const Iterator &)=default
std::conditional_t< Const, bool, typename word_type::reference > reference
Definition: bitdeque.h:49
Iterator(const Iterator &)=default
Default copy constructor.
bool const_reference
Definition: bitdeque.h:50
Iterator & operator-=(difference_type dist)
Definition: bitdeque.h:94
std::random_access_iterator_tag iterator_category
Definition: bitdeque.h:45
reference operator*() const
Definition: bitdeque.h:104
Iterator(const deque_iterator &it, int bitpos)
Definition: bitdeque.h:41
Iterator(const Iterator< false > &x)
Conversion from non-const to const iterator.
Definition: bitdeque.h:61
friend bool operator==(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:103
friend auto operator<=>(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:102
Iterator & operator++()
Definition: bitdeque.h:95
friend Iterator operator-(Iterator x, difference_type dist)
Definition: bitdeque.h:101
Iterator & operator+=(difference_type dist)
Definition: bitdeque.h:63
reference operator[](difference_type pos) const
Definition: bitdeque.h:105
friend Iterator operator+(Iterator x, difference_type dist)
Definition: bitdeque.h:99
friend difference_type operator-(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:88
Iterator operator++(int)
Definition: bitdeque.h:96
deque_iterator m_it
Definition: bitdeque.h:39
Iterator & operator--()
Definition: bitdeque.h:97
Iterator operator--(int)
Definition: bitdeque.h:98
friend Iterator operator+(difference_type dist, Iterator x)
Definition: bitdeque.h:100
Class that mimics std::deque<bool>, but with std::vector<bool>'s bit packing.
Definition: bitdeque.h:23
reference emplace_front(bool val)
Definition: bitdeque.h:366
void erase_front(size_type n)
Shrink the container by n bits, removing from the beginning.
Definition: bitdeque.h:163
void assign(std::initializer_list< bool > ilist)
Set the container equal to the bits in ilist.
Definition: bitdeque.h:289
int m_pad_begin
Number of unused bits at the front of m_deque.front().
Definition: bitdeque.h:126
std::deque< word_type > deque_type
Definition: bitdeque.h:26
const_iterator begin() const noexcept
Definition: bitdeque.h:246
void pointer
Definition: bitdeque.h:116
bitdeque(bitdeque &&) noexcept=default
Move constructor.
bitdeque(const bitdeque &)=default
Copy constructor.
void const_pointer
Definition: bitdeque.h:117
const_iterator end() const noexcept
Definition: bitdeque.h:248
size_type size() const noexcept
Count the number of bits in the container.
Definition: bitdeque.h:258
bool empty() const noexcept
Determine whether the container is empty.
Definition: bitdeque.h:261
bool const_reference
Definition: bitdeque.h:113
reference front()
Definition: bitdeque.h:328
typename deque_type::difference_type difference_type
Definition: bitdeque.h:111
void clear() noexcept
Empty the container.
Definition: bitdeque.h:340
reverse_iterator rend() noexcept
Definition: bitdeque.h:251
void assign(size_type count, bool val)
Set the container equal to count times the value of val.
Definition: bitdeque.h:211
typename word_type::reference reference
Definition: bitdeque.h:112
bitdeque & operator=(std::initializer_list< bool > ilist)
Set the container equal to the bits in ilist.
Definition: bitdeque.h:300
bitdeque()
Construct an empty container.
Definition: bitdeque.h:208
iterator end() noexcept
Definition: bitdeque.h:245
const_reference front() const
Definition: bitdeque.h:329
int m_pad_end
Number of unused bits at the back of m_deque.back().
Definition: bitdeque.h:129
const_reference at(size_type position) const
Definition: bitdeque.h:319
reverse_iterator rbegin() noexcept
Definition: bitdeque.h:250
reference back()
Definition: bitdeque.h:330
std::reverse_iterator< iterator > reverse_iterator
Definition: bitdeque.h:118
iterator erase(iterator first, iterator last)
Definition: bitdeque.h:422
std::size_t size_type
Definition: bitdeque.h:110
void extend_front(size_type n)
Extend the container by n bits, adding at the beginning.
Definition: bitdeque.h:182
friend void swap(bitdeque &b1, bitdeque &b2) noexcept
Definition: bitdeque.h:403
const_reverse_iterator crend() const noexcept
Definition: bitdeque.h:255
void shrink_to_fit()
Release unused memory.
Definition: bitdeque.h:334
bitdeque(It first, It last)
Construct a container containing the bits in [first,last).
Definition: bitdeque.h:308
bitdeque(size_type count, bool val)
Construct a container containing count times the value of val.
Definition: bitdeque.h:226
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: bitdeque.h:119
reference emplace_back(bool val)
Definition: bitdeque.h:352
void resize(size_type n)
Resize the container.
Definition: bitdeque.h:387
void assign(It first, It last)
Set the container equal to the bits in [first,last).
Definition: bitdeque.h:278
bool value_type
Definition: bitdeque.h:109
const_reverse_iterator rend() const noexcept
Definition: bitdeque.h:254
reference at(size_type position)
Definition: bitdeque.h:314
std::bitset< BITS_PER_WORD > word_type
Definition: bitdeque.h:25
void pop_back()
Definition: bitdeque.h:375
const_reference operator[](size_type position) const
Definition: bitdeque.h:327
size_type max_size() const noexcept
Return the maximum size of the container.
Definition: bitdeque.h:267
const_reverse_iterator crbegin() const noexcept
Definition: bitdeque.h:253
bitdeque(std::initializer_list< bool > ilist)
Construct a container containing the bits in ilist.
Definition: bitdeque.h:311
iterator insert(const_iterator pos, size_type count, bool val)
Definition: bitdeque.h:438
iterator erase(iterator pos)
Definition: bitdeque.h:424
deque_type m_deque
Deque of bitsets storing the actual bit data.
Definition: bitdeque.h:123
iterator insert(const_iterator pos, bool val)
Definition: bitdeque.h:427
void pop_front()
Definition: bitdeque.h:381
iterator erase(const_iterator first, const_iterator last)
Definition: bitdeque.h:406
bitdeque(size_t count)
Construct a container containing count false values.
Definition: bitdeque.h:229
void push_front(bool val)
Definition: bitdeque.h:361
void insert_zeroes(size_type before, size_type count)
Insert a sequence of falses anywhere in the container.
Definition: bitdeque.h:194
void swap(bitdeque &other) noexcept
Definition: bitdeque.h:397
iterator emplace(const_iterator pos, bool val)
Definition: bitdeque.h:436
iterator insert(const_iterator pos, It first, It last)
Definition: bitdeque.h:450
const_reference back() const
Definition: bitdeque.h:331
iterator begin() noexcept
Definition: bitdeque.h:244
const_reverse_iterator rbegin() const noexcept
Definition: bitdeque.h:252
iterator erase(const_iterator pos)
Definition: bitdeque.h:423
void erase_back(size_type n)
Shrink the container by n bits, removing from the end.
Definition: bitdeque.h:132
const_iterator cbegin() const noexcept
Definition: bitdeque.h:247
void push_back(bool val)
Definition: bitdeque.h:347
reference operator[](size_type position)
Definition: bitdeque.h:326
void extend_back(size_type n)
Extend the container by n bits, adding at the end.
Definition: bitdeque.h:151
const_iterator cend() const noexcept
Definition: bitdeque.h:249
static int count