Bitcoin Core 28.99.0
P2P Digital Currency
bitdeque.cpp
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#include <random.h>
7#include <test/fuzz/util.h>
8#include <util/bitdeque.h>
9
10#include <deque>
11#include <vector>
12
13namespace {
14
15constexpr int LEN_BITS = 16;
16constexpr int RANDDATA_BITS = 20;
17
18using bitdeque_type = bitdeque<128>;
19
21std::vector<bool> RANDDATA;
22
23void InitRandData()
24{
25 FastRandomContext ctx(true);
26 RANDDATA.clear();
27 for (size_t i = 0; i < (1U << RANDDATA_BITS) + (1U << LEN_BITS); ++i) {
28 RANDDATA.push_back(ctx.randbool());
29 }
30}
31
32} // namespace
33
34FUZZ_TARGET(bitdeque, .init = InitRandData)
35{
36 FuzzedDataProvider provider(buffer.data(), buffer.size());
37 FastRandomContext ctx(true);
38
39 size_t maxlen = (1U << provider.ConsumeIntegralInRange<size_t>(0, LEN_BITS)) - 1;
40 size_t limitlen = 4 * maxlen;
41
42 std::deque<bool> deq;
43 bitdeque_type bitdeq;
44
45 const auto& cdeq = deq;
46 const auto& cbitdeq = bitdeq;
47
48 size_t initlen = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
49 while (initlen) {
50 bool val = ctx.randbool();
51 deq.push_back(val);
52 bitdeq.push_back(val);
53 --initlen;
54 }
55
56 const auto iter_limit{maxlen > 6000 ? 90U : 900U};
57 LIMITED_WHILE(provider.remaining_bytes() > 0, iter_limit)
58 {
60 provider,
61 [&] {
62 // constructor()
63 deq = std::deque<bool>{};
64 bitdeq = bitdeque_type{};
65 },
66 [&] {
67 // clear()
68 deq.clear();
69 bitdeq.clear();
70 },
71 [&] {
72 // resize()
73 auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
74 deq.resize(count);
75 bitdeq.resize(count);
76 },
77 [&] {
78 // assign(count, val)
79 auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
80 bool val = ctx.randbool();
81 deq.assign(count, val);
82 bitdeq.assign(count, val);
83 },
84 [&] {
85 // constructor(count, val)
86 auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
87 bool val = ctx.randbool();
88 deq = std::deque<bool>(count, val);
89 bitdeq = bitdeque_type(count, val);
90 },
91 [&] {
92 // constructor(count)
93 auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
94 deq = std::deque<bool>(count);
95 bitdeq = bitdeque_type(count);
96 },
97 [&] {
98 // construct(begin, end)
99 auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
100 auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
101 auto rand_end = rand_begin + count;
102 deq = std::deque<bool>(rand_begin, rand_end);
103 bitdeq = bitdeque_type(rand_begin, rand_end);
104 },
105 [&] {
106 // assign(begin, end)
107 auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
108 auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
109 auto rand_end = rand_begin + count;
110 deq.assign(rand_begin, rand_end);
111 bitdeq.assign(rand_begin, rand_end);
112 },
113 [&] {
114 // construct(initializer_list)
115 std::initializer_list<bool> ilist{ctx.randbool(), ctx.randbool(), ctx.randbool(), ctx.randbool(), ctx.randbool()};
116 deq = std::deque<bool>(ilist);
117 bitdeq = bitdeque_type(ilist);
118 },
119 [&] {
120 // assign(initializer_list)
121 std::initializer_list<bool> ilist{ctx.randbool(), ctx.randbool(), ctx.randbool()};
122 deq.assign(ilist);
123 bitdeq.assign(ilist);
124 },
125 [&] {
126 // operator=(const&)
127 auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
128 bool val = ctx.randbool();
129 const std::deque<bool> deq2(count, val);
130 deq = deq2;
131 const bitdeque_type bitdeq2(count, val);
132 bitdeq = bitdeq2;
133 },
134 [&] {
135 // operator=(&&)
136 auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
137 bool val = ctx.randbool();
138 std::deque<bool> deq2(count, val);
139 deq = std::move(deq2);
140 bitdeque_type bitdeq2(count, val);
141 bitdeq = std::move(bitdeq2);
142 },
143 [&] {
144 // deque swap
145 auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
146 auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
147 auto rand_end = rand_begin + count;
148 std::deque<bool> deq2(rand_begin, rand_end);
149 bitdeque_type bitdeq2(rand_begin, rand_end);
150 using std::swap;
151 assert(deq.size() == bitdeq.size());
152 assert(deq2.size() == bitdeq2.size());
153 swap(deq, deq2);
154 swap(bitdeq, bitdeq2);
155 assert(deq.size() == bitdeq.size());
156 assert(deq2.size() == bitdeq2.size());
157 },
158 [&] {
159 // deque.swap
160 auto count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
161 auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
162 auto rand_end = rand_begin + count;
163 std::deque<bool> deq2(rand_begin, rand_end);
164 bitdeque_type bitdeq2(rand_begin, rand_end);
165 assert(deq.size() == bitdeq.size());
166 assert(deq2.size() == bitdeq2.size());
167 deq.swap(deq2);
168 bitdeq.swap(bitdeq2);
169 assert(deq.size() == bitdeq.size());
170 assert(deq2.size() == bitdeq2.size());
171 },
172 [&] {
173 // operator=(initializer_list)
174 std::initializer_list<bool> ilist{ctx.randbool(), ctx.randbool(), ctx.randbool()};
175 deq = ilist;
176 bitdeq = ilist;
177 },
178 [&] {
179 // iterator arithmetic
180 auto pos1 = provider.ConsumeIntegralInRange<long>(0, cdeq.size());
181 auto pos2 = provider.ConsumeIntegralInRange<long>(0, cdeq.size());
182 auto it = deq.begin() + pos1;
183 auto bitit = bitdeq.begin() + pos1;
184 if ((size_t)pos1 != cdeq.size()) assert(*it == *bitit);
185 assert(it - deq.begin() == pos1);
186 assert(bitit - bitdeq.begin() == pos1);
187 if (provider.ConsumeBool()) {
188 it += pos2 - pos1;
189 bitit += pos2 - pos1;
190 } else {
191 it -= pos1 - pos2;
192 bitit -= pos1 - pos2;
193 }
194 if ((size_t)pos2 != cdeq.size()) assert(*it == *bitit);
195 assert(deq.end() - it == bitdeq.end() - bitit);
196 if (provider.ConsumeBool()) {
197 if ((size_t)pos2 != cdeq.size()) {
198 ++it;
199 ++bitit;
200 }
201 } else {
202 if (pos2 != 0) {
203 --it;
204 --bitit;
205 }
206 }
207 assert(deq.end() - it == bitdeq.end() - bitit);
208 },
209 [&] {
210 // begin() and end()
211 assert(deq.end() - deq.begin() == bitdeq.end() - bitdeq.begin());
212 },
213 [&] {
214 // begin() and end() (const)
215 assert(cdeq.end() - cdeq.begin() == cbitdeq.end() - cbitdeq.begin());
216 },
217 [&] {
218 // rbegin() and rend()
219 assert(deq.rend() - deq.rbegin() == bitdeq.rend() - bitdeq.rbegin());
220 },
221 [&] {
222 // rbegin() and rend() (const)
223 assert(cdeq.rend() - cdeq.rbegin() == cbitdeq.rend() - cbitdeq.rbegin());
224 },
225 [&] {
226 // cbegin() and cend()
227 assert(cdeq.cend() - cdeq.cbegin() == cbitdeq.cend() - cbitdeq.cbegin());
228 },
229 [&] {
230 // crbegin() and crend()
231 assert(cdeq.crend() - cdeq.crbegin() == cbitdeq.crend() - cbitdeq.crbegin());
232 },
233 [&] {
234 // size() and maxsize()
235 assert(cdeq.size() == cbitdeq.size());
236 assert(cbitdeq.size() <= cbitdeq.max_size());
237 },
238 [&] {
239 // empty
240 assert(cdeq.empty() == cbitdeq.empty());
241 },
242 [&] {
243 // at (in range) and flip
244 if (!cdeq.empty()) {
245 size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 1);
246 auto& ref = deq.at(pos);
247 auto bitref = bitdeq.at(pos);
248 assert(ref == bitref);
249 if (ctx.randbool()) {
250 ref = !ref;
251 bitref.flip();
252 }
253 }
254 },
255 [&] {
256 // at (maybe out of range) and bit assign
257 size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() + maxlen);
258 bool newval = ctx.randbool();
259 bool throw_deq{false}, throw_bitdeq{false};
260 bool val_deq{false}, val_bitdeq{false};
261 try {
262 auto& ref = deq.at(pos);
263 val_deq = ref;
264 ref = newval;
265 } catch (const std::out_of_range&) {
266 throw_deq = true;
267 }
268 try {
269 auto ref = bitdeq.at(pos);
270 val_bitdeq = ref;
271 ref = newval;
272 } catch (const std::out_of_range&) {
273 throw_bitdeq = true;
274 }
275 assert(throw_deq == throw_bitdeq);
276 assert(throw_bitdeq == (pos >= cdeq.size()));
277 if (!throw_deq) assert(val_deq == val_bitdeq);
278 },
279 [&] {
280 // at (maybe out of range) (const)
281 size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() + maxlen);
282 bool throw_deq{false}, throw_bitdeq{false};
283 bool val_deq{false}, val_bitdeq{false};
284 try {
285 auto& ref = cdeq.at(pos);
286 val_deq = ref;
287 } catch (const std::out_of_range&) {
288 throw_deq = true;
289 }
290 try {
291 auto ref = cbitdeq.at(pos);
292 val_bitdeq = ref;
293 } catch (const std::out_of_range&) {
294 throw_bitdeq = true;
295 }
296 assert(throw_deq == throw_bitdeq);
297 assert(throw_bitdeq == (pos >= cdeq.size()));
298 if (!throw_deq) assert(val_deq == val_bitdeq);
299 },
300 [&] {
301 // operator[]
302 if (!cdeq.empty()) {
303 size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 1);
304 assert(deq[pos] == bitdeq[pos]);
305 if (ctx.randbool()) {
306 deq[pos] = !deq[pos];
307 bitdeq[pos].flip();
308 }
309 }
310 },
311 [&] {
312 // operator[] const
313 if (!cdeq.empty()) {
314 size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 1);
315 assert(deq[pos] == bitdeq[pos]);
316 }
317 },
318 [&] {
319 // front()
320 if (!cdeq.empty()) {
321 auto& ref = deq.front();
322 auto bitref = bitdeq.front();
323 assert(ref == bitref);
324 if (ctx.randbool()) {
325 ref = !ref;
326 bitref = !bitref;
327 }
328 }
329 },
330 [&] {
331 // front() const
332 if (!cdeq.empty()) {
333 auto& ref = cdeq.front();
334 auto bitref = cbitdeq.front();
335 assert(ref == bitref);
336 }
337 },
338 [&] {
339 // back() and swap(bool, ref)
340 if (!cdeq.empty()) {
341 auto& ref = deq.back();
342 auto bitref = bitdeq.back();
343 assert(ref == bitref);
344 if (ctx.randbool()) {
345 ref = !ref;
346 bitref.flip();
347 }
348 }
349 },
350 [&] {
351 // back() const
352 if (!cdeq.empty()) {
353 const auto& cdeq = deq;
354 const auto& cbitdeq = bitdeq;
355 auto& ref = cdeq.back();
356 auto bitref = cbitdeq.back();
357 assert(ref == bitref);
358 }
359 },
360 [&] {
361 // push_back()
362 if (cdeq.size() < limitlen) {
363 bool val = ctx.randbool();
364 if (cdeq.empty()) {
365 deq.push_back(val);
366 bitdeq.push_back(val);
367 } else {
368 size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 1);
369 auto& ref = deq[pos];
370 auto bitref = bitdeq[pos];
371 assert(ref == bitref);
372 deq.push_back(val);
373 bitdeq.push_back(val);
374 assert(ref == bitref); // references are not invalidated
375 }
376 }
377 },
378 [&] {
379 // push_front()
380 if (cdeq.size() < limitlen) {
381 bool val = ctx.randbool();
382 if (cdeq.empty()) {
383 deq.push_front(val);
384 bitdeq.push_front(val);
385 } else {
386 size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 1);
387 auto& ref = deq[pos];
388 auto bitref = bitdeq[pos];
389 assert(ref == bitref);
390 deq.push_front(val);
391 bitdeq.push_front(val);
392 assert(ref == bitref); // references are not invalidated
393 }
394 }
395 },
396 [&] {
397 // pop_back()
398 if (!cdeq.empty()) {
399 if (cdeq.size() == 1) {
400 deq.pop_back();
401 bitdeq.pop_back();
402 } else {
403 size_t pos = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 2);
404 auto& ref = deq[pos];
405 auto bitref = bitdeq[pos];
406 assert(ref == bitref);
407 deq.pop_back();
408 bitdeq.pop_back();
409 assert(ref == bitref); // references to other elements are not invalidated
410 }
411 }
412 },
413 [&] {
414 // pop_front()
415 if (!cdeq.empty()) {
416 if (cdeq.size() == 1) {
417 deq.pop_front();
418 bitdeq.pop_front();
419 } else {
420 size_t pos = provider.ConsumeIntegralInRange<size_t>(1, cdeq.size() - 1);
421 auto& ref = deq[pos];
422 auto bitref = bitdeq[pos];
423 assert(ref == bitref);
424 deq.pop_front();
425 bitdeq.pop_front();
426 assert(ref == bitref); // references to other elements are not invalidated
427 }
428 }
429 },
430 [&] {
431 // erase (in middle, single)
432 if (!cdeq.empty()) {
433 size_t before = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - 1);
434 size_t after = cdeq.size() - 1 - before;
435 auto it = deq.erase(cdeq.begin() + before);
436 auto bitit = bitdeq.erase(cbitdeq.begin() + before);
437 assert(it == cdeq.begin() + before && it == cdeq.end() - after);
438 assert(bitit == cbitdeq.begin() + before && bitit == cbitdeq.end() - after);
439 }
440 },
441 [&] {
442 // erase (at front, range)
443 size_t count = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size());
444 auto it = deq.erase(cdeq.begin(), cdeq.begin() + count);
445 auto bitit = bitdeq.erase(cbitdeq.begin(), cbitdeq.begin() + count);
446 assert(it == deq.begin());
447 assert(bitit == bitdeq.begin());
448 },
449 [&] {
450 // erase (at back, range)
451 size_t count = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size());
452 auto it = deq.erase(cdeq.end() - count, cdeq.end());
453 auto bitit = bitdeq.erase(cbitdeq.end() - count, cbitdeq.end());
454 assert(it == deq.end());
455 assert(bitit == bitdeq.end());
456 },
457 [&] {
458 // erase (in middle, range)
459 size_t count = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size());
460 size_t before = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size() - count);
461 size_t after = cdeq.size() - count - before;
462 auto it = deq.erase(cdeq.begin() + before, cdeq.end() - after);
463 auto bitit = bitdeq.erase(cbitdeq.begin() + before, cbitdeq.end() - after);
464 assert(it == cdeq.begin() + before && it == cdeq.end() - after);
465 assert(bitit == cbitdeq.begin() + before && bitit == cbitdeq.end() - after);
466 },
467 [&] {
468 // insert/emplace (in middle, single)
469 if (cdeq.size() < limitlen) {
470 size_t before = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size());
471 bool val = ctx.randbool();
472 bool do_emplace = provider.ConsumeBool();
473 auto it = deq.insert(cdeq.begin() + before, val);
474 auto bitit = do_emplace ? bitdeq.emplace(cbitdeq.begin() + before, val)
475 : bitdeq.insert(cbitdeq.begin() + before, val);
476 assert(it == deq.begin() + before);
477 assert(bitit == bitdeq.begin() + before);
478 }
479 },
480 [&] {
481 // insert (at front, begin/end)
482 if (cdeq.size() < limitlen) {
483 size_t count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
484 auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
485 auto rand_end = rand_begin + count;
486 auto it = deq.insert(cdeq.begin(), rand_begin, rand_end);
487 auto bitit = bitdeq.insert(cbitdeq.begin(), rand_begin, rand_end);
488 assert(it == cdeq.begin());
489 assert(bitit == cbitdeq.begin());
490 }
491 },
492 [&] {
493 // insert (at back, begin/end)
494 if (cdeq.size() < limitlen) {
495 size_t count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
496 auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
497 auto rand_end = rand_begin + count;
498 auto it = deq.insert(cdeq.end(), rand_begin, rand_end);
499 auto bitit = bitdeq.insert(cbitdeq.end(), rand_begin, rand_end);
500 assert(it == cdeq.end() - count);
501 assert(bitit == cbitdeq.end() - count);
502 }
503 },
504 [&] {
505 // insert (in middle, range)
506 if (cdeq.size() < limitlen) {
507 size_t count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
508 size_t before = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size());
509 bool val = ctx.randbool();
510 auto it = deq.insert(cdeq.begin() + before, count, val);
511 auto bitit = bitdeq.insert(cbitdeq.begin() + before, count, val);
512 assert(it == deq.begin() + before);
513 assert(bitit == bitdeq.begin() + before);
514 }
515 },
516 [&] {
517 // insert (in middle, begin/end)
518 if (cdeq.size() < limitlen) {
519 size_t count = provider.ConsumeIntegralInRange<size_t>(0, maxlen);
520 size_t before = provider.ConsumeIntegralInRange<size_t>(0, cdeq.size());
521 auto rand_begin = RANDDATA.begin() + ctx.randbits(RANDDATA_BITS);
522 auto rand_end = rand_begin + count;
523 auto it = deq.insert(cdeq.begin() + before, rand_begin, rand_end);
524 auto bitit = bitdeq.insert(cbitdeq.begin() + before, rand_begin, rand_end);
525 assert(it == deq.begin() + before);
526 assert(bitit == bitdeq.begin() + before);
527 }
528 });
529 }
530 {
531 assert(deq.size() == bitdeq.size());
532 auto it = deq.begin();
533 auto bitit = bitdeq.begin();
534 auto itend = deq.end();
535 while (it != itend) {
536 assert(*it == *bitit);
537 ++it;
538 ++bitit;
539 }
540 }
541}
FUZZ_TARGET(bitdeque,.init=InitRandData)
Definition: bitdeque.cpp:34
Fast randomness source.
Definition: random.h:377
T ConsumeIntegralInRange(T min, T max)
bool randbool() noexcept
Generate a random boolean.
Definition: random.h:316
uint64_t randbits(int bits) noexcept
Generate a random (bits)-bit integer.
Definition: random.h:204
Class that mimics std::deque<bool>, but with std::vector<bool>'s bit packing.
Definition: bitdeque.h:23
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
Definition: fuzz.h:22
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
Definition: util.h:35
static int count
assert(!tx.IsCoinBase())