Bitcoin Core Fuzz Coverage Report

Coverage Report

Created: 2026-03-24 13:57

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