Bitcoin Core  31.0.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 
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 
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 
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;
94  Iterator& operator-=(difference_type dist) { return operator+=(-dist); }
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 
108 public:
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 
121 private:
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 
206 public:
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  }
319  const_reference at(size_type position) const
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();
343  m_pad_begin = m_pad_end = 0;
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.
381  void pop_front()
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
void resize(size_type n)
Resize the container.
Definition: bitdeque.h:387
void pointer
Definition: bitdeque.h:116
Iterator & operator++()
Definition: bitdeque.h:95
int ret
std::deque< word_type > deque_type
Definition: bitdeque.h:26
Iterator operator--(int)
Definition: bitdeque.h:98
void pop_front()
Definition: bitdeque.h:381
reference emplace_back(bool val)
Definition: bitdeque.h:352
bool const_reference
Definition: bitdeque.h:50
Iterator(const deque_iterator &it, int bitpos)
Definition: bitdeque.h:41
iterator begin() noexcept
Definition: bitdeque.h:244
Iterator()=default
Default constructor.
std::bitset< BITS_PER_WORD > word_type
Definition: bitdeque.h:25
typename deque_type::difference_type difference_type
Definition: bitdeque.h:111
std::size_t size_type
Definition: bitdeque.h:110
int m_pad_begin
Number of unused bits at the front of m_deque.front().
Definition: bitdeque.h:126
const_iterator end() const noexcept
Definition: bitdeque.h:248
void shrink_to_fit()
Release unused memory.
Definition: bitdeque.h:334
friend Iterator operator+(Iterator x, difference_type dist)
Definition: bitdeque.h:99
Iterator & operator-=(difference_type dist)
Definition: bitdeque.h:94
friend bool operator==(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:103
void assign(It first, It last)
Set the container equal to the bits in [first,last).
Definition: bitdeque.h:278
iterator insert(const_iterator pos, It first, It last)
Definition: bitdeque.h:450
Iterator to a bitdeque element, const or not.
Definition: bitdeque.h:30
size_type size() const noexcept
Count the number of bits in the container.
Definition: bitdeque.h:258
const_iterator cend() const noexcept
Definition: bitdeque.h:249
deque_type m_deque
Deque of bitsets storing the actual bit data.
Definition: bitdeque.h:123
iterator erase(const_iterator pos)
Definition: bitdeque.h:423
void extend_front(size_type n)
Extend the container by n bits, adding at the beginning.
Definition: bitdeque.h:182
const_reference back() const
Definition: bitdeque.h:331
bitdeque(size_t count)
Construct a container containing count false values.
Definition: bitdeque.h:229
bitdeque & operator=(std::initializer_list< bool > ilist)
Set the container equal to the bits in ilist.
Definition: bitdeque.h:300
bool const_reference
Definition: bitdeque.h:113
const_iterator begin() const noexcept
Definition: bitdeque.h:246
reference back()
Definition: bitdeque.h:330
bitdeque()
Construct an empty container.
Definition: bitdeque.h:208
reverse_iterator rbegin() noexcept
Definition: bitdeque.h:250
void swap(bitdeque &other) noexcept
Definition: bitdeque.h:397
friend Iterator operator-(Iterator x, difference_type dist)
Definition: bitdeque.h:101
iterator insert(const_iterator pos, size_type count, bool val)
Definition: bitdeque.h:438
bool value_type
Definition: bitdeque.h:109
std::reverse_iterator< iterator > reverse_iterator
Definition: bitdeque.h:118
void push_front(bool val)
Definition: bitdeque.h:361
const_reverse_iterator crbegin() const noexcept
Definition: bitdeque.h:253
Iterator & operator+=(difference_type dist)
Definition: bitdeque.h:63
Iterator(const Iterator< false > &x)
Conversion from non-const to const iterator.
Definition: bitdeque.h:61
const_reverse_iterator crend() const noexcept
Definition: bitdeque.h:255
const_iterator cbegin() const noexcept
Definition: bitdeque.h:247
reference operator[](size_type position)
Definition: bitdeque.h:326
reference front()
Definition: bitdeque.h:328
void assign(size_type count, bool val)
Set the container equal to count times the value of val.
Definition: bitdeque.h:211
Iterator operator++(int)
Definition: bitdeque.h:96
const_reference operator[](size_type position) const
Definition: bitdeque.h:327
iterator end() noexcept
Definition: bitdeque.h:245
deque_iterator m_it
Definition: bitdeque.h:39
void const_pointer
Definition: bitdeque.h:117
bool empty() const noexcept
Determine whether the container is empty.
Definition: bitdeque.h:261
void assign(std::initializer_list< bool > ilist)
Set the container equal to the bits in ilist.
Definition: bitdeque.h:289
const_reference at(size_type position) const
Definition: bitdeque.h:319
bitdeque(It first, It last)
Construct a container containing the bits in [first,last).
Definition: bitdeque.h:308
void pop_back()
Definition: bitdeque.h:375
bitdeque(size_type count, bool val)
Construct a container containing count times the value of val.
Definition: bitdeque.h:226
reverse_iterator rend() noexcept
Definition: bitdeque.h:251
reference at(size_type position)
Definition: bitdeque.h:314
Iterator & operator=(const Iterator &)=default
iterator erase(const_iterator first, const_iterator last)
Definition: bitdeque.h:406
std::conditional_t< Const, typename deque_type::const_iterator, typename deque_type::iterator > deque_iterator
Definition: bitdeque.h:37
const_reference front() const
Definition: bitdeque.h:329
iterator insert(const_iterator pos, bool val)
Definition: bitdeque.h:427
int m_pad_end
Number of unused bits at the back of m_deque.back().
Definition: bitdeque.h:129
std::ptrdiff_t difference_type
Definition: bitdeque.h:51
iterator erase(iterator pos)
Definition: bitdeque.h:424
void insert_zeroes(size_type before, size_type count)
Insert a sequence of falses anywhere in the container.
Definition: bitdeque.h:194
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
size_type max_size() const noexcept
Return the maximum size of the container.
Definition: bitdeque.h:267
Class that mimics std::deque<bool>, but with std::vector<bool>&#39;s bit packing.
Definition: bitdeque.h:22
typename word_type::reference reference
Definition: bitdeque.h:112
const_reverse_iterator rend() const noexcept
Definition: bitdeque.h:254
friend Iterator operator+(difference_type dist, Iterator x)
Definition: bitdeque.h:100
friend difference_type operator-(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:88
static int count
void clear() noexcept
Empty the container.
Definition: bitdeque.h:340
std::random_access_iterator_tag iterator_category
Definition: bitdeque.h:45
reference operator*() const
Definition: bitdeque.h:104
void erase_back(size_type n)
Shrink the container by n bits, removing from the end.
Definition: bitdeque.h:132
std::conditional_t< Const, bool, typename word_type::reference > reference
Definition: bitdeque.h:49
const_reverse_iterator rbegin() const noexcept
Definition: bitdeque.h:252
Iterator & operator--()
Definition: bitdeque.h:97
reference operator[](difference_type pos) const
Definition: bitdeque.h:105
void extend_back(size_type n)
Extend the container by n bits, adding at the end.
Definition: bitdeque.h:151
friend void swap(bitdeque &b1, bitdeque &b2) noexcept
Definition: bitdeque.h:403
iterator emplace(const_iterator pos, bool val)
Definition: bitdeque.h:436
bitdeque(std::initializer_list< bool > ilist)
Construct a container containing the bits in ilist.
Definition: bitdeque.h:311
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: bitdeque.h:119
void push_back(bool val)
Definition: bitdeque.h:347
iterator erase(iterator first, iterator last)
Definition: bitdeque.h:422