Bitcoin ABC  0.29.4
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 
22 template <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;
82  m_bitpos = BITS_PER_WORD - 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;
96  Iterator &operator-=(difference_type dist) { return operator+=(-dist); }
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 
159 public:
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 
172 private:
175 
178 
181 
184  if (n >= static_cast<size_type>(BITS_PER_WORD - m_pad_end)) {
185  n -= 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;
205  m_pad_end = BITS_PER_WORD - 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)) {
215  n -= 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 
255 public:
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()}; }
309  const_reverse_iterator rbegin() const noexcept {
310  return const_reverse_iterator{cend()};
311  }
312  const_reverse_iterator crbegin() const noexcept {
313  return const_reverse_iterator{cend()};
314  }
315  const_reverse_iterator rend() const noexcept {
316  return const_reverse_iterator{cbegin()};
317  }
318  const_reverse_iterator crend() const noexcept {
319  return const_reverse_iterator{cbegin()};
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.
377  reference at(size_type position) {
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();
404  m_pad_begin = m_pad_end = 0;
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 
438  void resize(size_type n) {
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.
479  iterator insert(const_iterator pos, bool val) {
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--(int)
Definition: bitdeque.h:118
deque_iterator m_it
Definition: bitdeque.h:39
Iterator(const deque_iterator &it, int bitpos)
Definition: bitdeque.h:41
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++()
Definition: bitdeque.h:97
Iterator()=default
Default constructor.
std::random_access_iterator_tag iterator_category
Definition: bitdeque.h:46
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
Iterator & operator--()
Definition: bitdeque.h:110
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
Iterator & operator=(const Iterator &)=default
friend bool operator>(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:138
reference operator[](difference_type pos) const
Definition: bitdeque.h:154
Iterator & operator-=(difference_type dist)
Definition: bitdeque.h:96
friend bool operator<=(const Iterator &x, const Iterator &y)
Definition: bitdeque.h:141
Iterator & operator+=(difference_type dist)
Definition: bitdeque.h:67
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
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
bitdeque & operator=(std::initializer_list< bool > ilist)
Set the container equal to the bits in ilist.
Definition: bitdeque.h:365
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:28
bool Const(const std::string &str, Span< const char > &sp)
Parse a constant.
Definition: spanparsing.cpp:14
static int count
Definition: tests.c:31