1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifdef PANDA_CATCH2
17 #include "util/bit_vector.h"
18 #include "util/set_operations.h"
19 #include "util/range.h"
20 #include "util/lazy.h"
21
22 #include <catch2/catch.hpp>
23 #include <rapidcheck/catch.h>
24 #include "util/tests/environment.h"
25
26 #include <cstdint>
27 #include <initializer_list>
28 #include <string>
29 #include <set>
30
31 using namespace panda::verifier;
32
33 using StdSet = std::set<size_t>;
34
35 struct BSet {
36 StdSet Indices;
37 BitVector Bits;
38
IsEqualBSet39 bool IsEqual() const
40 {
41 if (Bits.SetBitsCount() != Indices.size()) {
42 return false;
43 }
44 for (const auto &elem : Indices) {
45 if (!Bits[elem]) {
46 return false;
47 }
48 }
49 return true;
50 }
51 };
52
showValue(const BSet & bitset,std::ostream & os)53 void showValue(const BSet &bitset, std::ostream &os)
54 {
55 os << "BitSet{ .Indices {";
56 bool comma = false;
57 for (auto idx : bitset.Indices) {
58 if (comma) {
59 os << ", ";
60 }
61 comma = true;
62 os << idx;
63 }
64 os << "}, ";
65 os << ".Bits = {";
66 for (size_t idx = 0; idx < bitset.Bits.size(); ++idx) {
67 os << (static_cast<int>(bitset.Bits[idx]) ? '1' : '0');
68 if (((idx + 1) & 0x7) == 0) {
69 os << ' ';
70 }
71 if (((idx + 1) & 0x1F) == 0) {
72 os << ' ';
73 }
74 }
75 os << "} }";
76 }
77
78 namespace rc {
79
80 constexpr size_t max_value = 1024U;
81 auto value_gen = gen::inRange<size_t>(0, max_value);
82
83 template <>
84 struct Arbitrary<BSet> {
arbitraryrc::Arbitrary85 static Gen<BSet> arbitrary()
86 {
87 auto set_n_inc = gen::pair(gen::container<std::set<size_t>>(value_gen), gen::inRange(1, 100)); // N = 100
88 return gen::map(set_n_inc, [](auto param_set_n_inc) {
89 auto &[set, inc] = param_set_n_inc;
90 size_t size = (set.empty() ? 0 : *set.rbegin()) + inc;
91 BitVector bits {size};
92 for (const auto &idx : set) {
93 bits[idx] = 1;
94 }
95 return BSet {set, bits};
96 });
97 }
98 };
99
100 template <>
101 struct Arbitrary<Range<size_t>> {
arbitraryrc::Arbitrary102 static Gen<Range<size_t>> arbitrary()
103 {
104 return gen::map(gen::pair(value_gen, value_gen), [](auto pair) {
105 return Range<size_t> {std::min(pair.first, pair.second), std::max(pair.first, pair.second)};
106 });
107 }
108 };
109
110 } // namespace rc
111
112 namespace panda::verifier::test {
113
114 using namespace rc;
115
116 using Interval = panda::verifier::Range<size_t>;
117 using Intervals = std::initializer_list<Interval>;
118
ClassifySize(std::string name,size_t size,const Intervals & intervals)119 void ClassifySize(std::string name, size_t size, const Intervals &intervals)
120 {
121 for (const auto &i : intervals) {
122 RC_CLASSIFY(i.Contains(size), name + " " + std::to_string(i));
123 }
124 }
125
126 const EnvOptions Options {"VERIFIER_TEST"};
127
128 Intervals stat_intervals = {{0, 10U}, {11U, 50U}, {51U, 100U}, {101U, max_value}};
129
stat(const BSet & bitset)130 void stat(const BSet &bitset)
131 {
132 if (Options.Get<bool>("verbose", false)) {
133 ClassifySize("Bits.size() in", bitset.Bits.size(), stat_intervals);
134 ClassifySize("Indices.size() in", bitset.Indices.size(), stat_intervals);
135 }
136 }
137
Universum(size_t size)138 StdSet Universum(size_t size)
139 {
140 return ToSet<StdSet>(Interval(0, size - 1));
141 }
142
143 TEST_CASE("Test bitvector", "verifier_bitvector")
144 {
145 SECTION("Basic tests")
146 {
__anonea1bced30302(const BSet &bit_set) 147 prop("SetBitsCount()", [](const BSet &bit_set) {
148 stat(bit_set);
149 RC_ASSERT(bit_set.Bits.SetBitsCount() == bit_set.Indices.size());
150 });
__anonea1bced30402(const BSet &bit_set) 151 prop("operator=", [](const BSet &bit_set) {
152 stat(bit_set);
153 auto bits = bit_set.Bits;
154 RC_ASSERT(bits.size() == bit_set.Bits.size());
155 for (size_t idx = 0; idx < bits.size(); ++idx) {
156 RC_ASSERT(bits[idx] == bit_set.Bits[idx]);
157 }
158 RC_ASSERT(bits.SetBitsCount() == bit_set.Bits.SetBitsCount());
159 });
__anonea1bced30502(BSet &&bset) 160 prop("clr()", [](BSet &&bset) {
161 stat(bset);
162 bset.Bits.clr();
163 RC_ASSERT(bset.Bits.SetBitsCount() == 0U);
164 });
__anonea1bced30602(BSet &&bset) 165 prop("set()", [](BSet &&bset) {
166 stat(bset);
167 bset.Bits.set();
168 RC_ASSERT(bset.Bits.SetBitsCount() == bset.Bits.size());
169 });
__anonea1bced30702(BSet &&bset) 170 prop("invert()", [](BSet &&bset) {
171 stat(bset);
172 auto zero_bits = bset.Bits.size() - bset.Bits.SetBitsCount();
173 bset.Bits.invert();
174 RC_ASSERT(bset.Bits.SetBitsCount() == zero_bits);
175 });
__anonea1bced30802(BSet &&bset, std::set<size_t> &&indices) 176 prop("Clr(size_t idx)", [](BSet &&bset, std::set<size_t> &&indices) {
177 stat(bset);
178 auto size = bset.Bits.size();
179 for (const auto &idx : indices) {
180 bset.Bits.Clr(idx % size);
181 bset.Indices.erase(idx % size);
182 }
183 RC_ASSERT(bset.Bits.SetBitsCount() == bset.Indices.size());
184 });
__anonea1bced30902(BSet &&bset, std::set<size_t> &&indices) 185 prop("Set(size_t idx)", [](BSet &&bset, std::set<size_t> &&indices) {
186 stat(bset);
187 auto size = bset.Bits.size();
188 for (const auto &idx : indices) {
189 auto i = idx % size;
190 bset.Bits.Set(i);
191 bset.Indices.insert(i);
192 }
193 RC_ASSERT(bset.Bits.SetBitsCount() == bset.Indices.size());
194 });
__anonea1bced30a02(BSet &&bset, std::set<size_t> &&indices) 195 prop("invert(size_t idx)", [](BSet &&bset, std::set<size_t> &&indices) {
196 stat(bset);
197 auto size = bset.Bits.size();
198 for (const auto &idx : indices) {
199 auto i = idx % size;
200 bset.Bits.invert(i);
201 if (bset.Indices.count(i) > 0) {
202 bset.Indices.erase(i);
203 } else {
204 bset.Indices.insert(i);
205 }
206 }
207 RC_ASSERT(bset.Bits.SetBitsCount() == bset.Indices.size());
208 });
__anonea1bced30b02(BSet &&bset, Interval &&interval) 209 prop("clr(size_t from, size_t to)", [](BSet &&bset, Interval &&interval) {
210 RC_PRE(interval.End() < bset.Bits.size());
211 stat(bset);
212 bset.Bits.Clr(interval.Start(), interval.End());
213 for (auto idx : interval) {
214 bset.Indices.erase(idx);
215 }
216 RC_ASSERT(bset.Bits.SetBitsCount() == bset.Indices.size());
217 });
__anonea1bced30c02(BSet &&bset, Interval &&interval) 218 prop("set(size_t from, size_t to)", [](BSet &&bset, Interval &&interval) {
219 RC_PRE(interval.End() < bset.Bits.size());
220 stat(bset);
221 bset.Bits.Set(interval.Start(), interval.End());
222 for (auto idx : interval) {
223 bset.Indices.insert(idx);
224 }
225 RC_ASSERT(bset.Bits.SetBitsCount() == bset.Indices.size());
226 });
__anonea1bced30d02(BSet &&bset, Interval &&interval) 227 prop("invert(size_t from, size_t to)", [](BSet &&bset, Interval &&interval) {
228 RC_PRE(interval.End() < bset.Bits.size());
229 stat(bset);
230 bset.Bits.invert(interval.Start(), interval.End());
231 for (auto idx : interval) {
232 if (bset.Indices.count(idx) > 0) {
233 bset.Indices.erase(idx);
234 } else {
235 bset.Indices.insert(idx);
236 }
237 }
238 RC_ASSERT(bset.Bits.SetBitsCount() == bset.Indices.size());
239 });
__anonea1bced30e02(BSet &&lhs, BSet &&rhs) 240 prop("operator&=", [](BSet &&lhs, BSet &&rhs) {
241 stat(rhs);
242 stat(lhs);
243 lhs.Bits &= rhs.Bits;
244 lhs.Indices = SetIntersection(lhs.Indices, rhs.Indices);
245 RC_ASSERT(lhs.IsEqual());
246 });
__anonea1bced30f02(BSet &&lhs, BSet &&rhs) 247 prop("operator|=", [](BSet &&lhs, BSet &&rhs) {
248 stat(rhs);
249 stat(lhs);
250 StdSet universum = Universum(std::max(lhs.Bits.size(), rhs.Bits.size()));
251 StdSet clamped = SetIntersection(rhs.Indices, universum);
252 lhs.Bits |= rhs.Bits;
253 lhs.Indices = SetUnion(lhs.Indices, clamped);
254 RC_ASSERT(lhs.IsEqual());
255 });
__anonea1bced31002(BSet &&lhs, BSet &&rhs) 256 prop("operator^=", [](BSet &&lhs, BSet &&rhs) {
257 stat(rhs);
258 stat(lhs);
259 lhs.Bits ^= rhs.Bits;
260 lhs.Indices = SetDifference(SetUnion(lhs.Indices, rhs.Indices), SetIntersection(lhs.Indices, rhs.Indices));
261 RC_ASSERT(lhs.IsEqual());
262 });
__anonea1bced31102(BSet &&bset, size_t new_size) 263 prop("resize(size_t)", [](BSet &&bset, size_t new_size) {
264 stat(bset);
265 new_size %= bset.Bits.size();
266 bset.Bits.resize(new_size);
267 auto universum = Universum(new_size);
268 bset.Indices = SetIntersection(universum, bset.Indices);
269 RC_ASSERT(bset.Bits.SetBitsCount() == bset.Indices.size());
270 RC_ASSERT(bset.Bits.size() == new_size);
271 });
272 }
273 SECTION("Iterators")
274 {
__anonea1bced31202(BSet &&bset) 275 prop("for_all_idx_val(Handler)", [](BSet &&bset) {
276 stat(bset);
277 StdSet selected;
278 auto handler = [&selected](auto idx, auto val) {
279 while (val) {
280 if (val & 1U) {
281 selected.insert(idx);
282 }
283 val >>= 1U;
284 ++idx;
285 }
286 return true;
287 };
288 bset.Bits.for_all_idx_val(handler);
289 RC_ASSERT(selected == bset.Indices);
290 });
__anonea1bced31402(BSet &&bset) 291 prop("for_all_idx_of<1>(Handler)", [](BSet &&bset) {
292 stat(bset);
293 StdSet result;
294 bset.Bits.for_all_idx_of<1>([&result](auto idx) {
295 result.insert(idx);
296 return true;
297 });
298 RC_ASSERT(result == bset.Indices);
299 });
__anonea1bced31602(BSet &&bset) 300 prop("for_all_idx_of<0>(Handler)", [](BSet &&bset) {
301 stat(bset);
302 StdSet result;
303 bset.Bits.for_all_idx_of<0>([&result](auto idx) {
304 result.insert(idx);
305 return true;
306 });
307 StdSet universum = Universum(bset.Bits.size());
308 RC_ASSERT(result == SetDifference(universum, bset.Indices));
309 });
310 }
311 SECTION("Lazy iterators")
312 {
__anonea1bced31802(BSet &&bset) 313 prop("LazyIndicesOf<1>(from, to)", [](BSet &&bset) {
314 stat(bset);
315 size_t from = *gen::inRange<size_t>(0, bset.Bits.size() - 1);
316 size_t to = *gen::oneOf(gen::inRange<size_t>(from, bset.Bits.size()),
317 gen::just(std::numeric_limits<size_t>::max()));
318 auto result = ContainerOf<StdSet>(bset.Bits.LazyIndicesOf<1>(from, to));
319 StdSet expected = bset.Indices;
320 if (from > 0) {
321 expected.erase(expected.begin(), expected.lower_bound(from));
322 }
323 if (!expected.empty() && to < *expected.rbegin()) {
324 expected.erase(expected.upper_bound(to), expected.end());
325 }
326 RC_ASSERT(result == expected);
327 });
__anonea1bced31902(BSet &&bset) 328 prop("LazyIndicesOf<0>(from)", [](BSet &&bset) {
329 stat(bset);
330 size_t from = *gen::inRange<size_t>(0, bset.Bits.size() - 1);
331 auto result = ContainerOf<StdSet>(bset.Bits.LazyIndicesOf<0>(from));
332 StdSet universum = Universum(bset.Bits.size());
333 StdSet expected = SetDifference(universum, bset.Indices);
334 if (from > 0) {
335 expected.erase(expected.begin(), expected.lower_bound(from));
336 }
337 RC_ASSERT(result == expected);
338 });
339 }
340 SECTION("Power of folded bitsets")
341 {
__anonea1bced31a02(BSet &&bset1, BSet &&bset2) 342 prop("power_of_and(arg,arg)", [](BSet &&bset1, BSet &&bset2) {
343 stat(bset1);
344 stat(bset2);
345 auto result = BitVector::power_of_and(bset1.Bits, bset2.Bits);
346 RC_ASSERT(result == SetIntersection(bset1.Indices, bset2.Indices).size());
347 });
__anonea1bced31b02(BSet &&bset1, BSet &&bset2, BSet &&bset3) 348 prop("power_of_and(arg,arg,arg)", [](BSet &&bset1, BSet &&bset2, BSet &&bset3) {
349 stat(bset1);
350 stat(bset2);
351 stat(bset3);
352 auto result = BitVector::power_of_and(bset1.Bits, bset2.Bits, bset3.Bits);
353 RC_ASSERT(result == SetIntersection(bset1.Indices, bset2.Indices, bset3.Indices).size());
354 });
__anonea1bced31c02(BSet &&bset1, BSet &&bset2) 355 prop("power_of_or(arg,arg)", [](BSet &&bset1, BSet &&bset2) {
356 stat(bset1);
357 stat(bset2);
358 auto result = BitVector::power_of_or(bset1.Bits, bset2.Bits);
359 auto size = std::min(bset1.Bits.size(), bset2.Bits.size());
360 auto universum = Universum(size);
361 RC_ASSERT(result == SetIntersection(universum, SetUnion(bset1.Indices, bset2.Indices)).size());
362 });
__anonea1bced31d02(BSet &&bset1, BSet &&bset2, BSet &&bset3) 363 prop("power_of_or(arg,arg,arg)", [](BSet &&bset1, BSet &&bset2, BSet &&bset3) {
364 stat(bset1);
365 stat(bset2);
366 stat(bset3);
367 auto result = BitVector::power_of_or(bset1.Bits, bset2.Bits, bset3.Bits);
368 auto size = std::min(std::min(bset1.Bits.size(), bset2.Bits.size()), bset3.Bits.size());
369 auto universum = Universum(size);
370 RC_ASSERT(result ==
371 SetIntersection(universum, SetUnion(bset1.Indices, bset2.Indices, bset3.Indices)).size());
372 });
__anonea1bced31e02(BSet &&bset1, BSet &&bset2) 373 prop("power_of_xor(arg,arg)", [](BSet &&bset1, BSet &&bset2) {
374 stat(bset1);
375 stat(bset2);
376 auto result = BitVector::power_of_xor(bset1.Bits, bset2.Bits);
377 auto size = std::min(bset1.Bits.size(), bset2.Bits.size());
378 auto universum = Universum(size);
379 auto set_result = SetIntersection(universum, SetDifference(SetUnion(bset1.Indices, bset2.Indices),
380 SetIntersection(bset1.Indices, bset2.Indices)));
381 RC_ASSERT(result == set_result.size());
382 });
__anonea1bced31f02(BSet &&bset1, BSet &&bset2, BSet &&bset3) 383 prop("power_of_xor(arg,arg,arg)", [](BSet &&bset1, BSet &&bset2, BSet &&bset3) {
384 stat(bset1);
385 stat(bset2);
386 stat(bset3);
387 auto result = BitVector::power_of_xor(bset1.Bits, bset2.Bits, bset3.Bits);
388 auto size = std::min(std::min(bset1.Bits.size(), bset2.Bits.size()), bset3.Bits.size());
389 auto universum = Universum(size);
390 auto xor1 =
391 SetDifference(SetUnion(bset1.Indices, bset2.Indices), SetIntersection(bset1.Indices, bset2.Indices));
392 auto xor2 = SetDifference(SetUnion(xor1, bset3.Indices), SetIntersection(xor1, bset3.Indices));
393 auto set_result = SetIntersection(universum, xor2);
394 RC_ASSERT(result == set_result.size());
395 });
__anonea1bced32002(BSet &&bset1, BSet &&bset2) 396 prop("power_of_and_not(arg,arg)", [](BSet &&bset1, BSet &&bset2) {
397 stat(bset1);
398 stat(bset2);
399 auto result = BitVector::power_of_and_not(bset1.Bits, bset2.Bits);
400 auto size = std::min(bset1.Bits.size(), bset2.Bits.size());
401 auto universum = Universum(size);
402 auto set_result = SetIntersection(universum, SetDifference(bset1.Indices, bset2.Indices));
403 RC_ASSERT(result == set_result.size());
404 });
405 }
406 SECTION("Lazy iterators over folded bitsets")
407 {
__anonea1bced32102(BSet &&bset1, BSet &&bset2, BSet &&bset3) 408 prop("lazy_and_then_indices_of<1>()", [](BSet &&bset1, BSet &&bset2, BSet &&bset3) {
409 stat(bset1);
410 stat(bset2);
411 stat(bset3);
412 auto result =
413 ContainerOf<StdSet>(BitVector::lazy_and_then_indices_of<1>(bset1.Bits, bset2.Bits, bset3.Bits));
414 auto size = std::min(std::min(bset1.Bits.size(), bset2.Bits.size()), bset3.Bits.size());
415 auto universum = Universum(size);
416 auto set_result = SetIntersection(universum, bset1.Indices, bset2.Indices, bset3.Indices);
417 RC_ASSERT(result == set_result);
418 });
__anonea1bced32202(BSet &&bset1, BSet &&bset2, BSet &&bset3) 419 prop("lazy_and_then_indices_of<0>()", [](BSet &&bset1, BSet &&bset2, BSet &&bset3) {
420 stat(bset1);
421 stat(bset2);
422 stat(bset3);
423 auto result =
424 ContainerOf<StdSet>(BitVector::lazy_and_then_indices_of<0>(bset1.Bits, bset2.Bits, bset3.Bits));
425 auto size = std::min(std::min(bset1.Bits.size(), bset2.Bits.size()), bset3.Bits.size());
426 auto universum = Universum(size);
427 auto set_result = SetDifference(universum, SetIntersection(bset1.Indices, bset2.Indices, bset3.Indices));
428 RC_ASSERT(result == set_result);
429 });
__anonea1bced32302(BSet &&bset1, BSet &&bset2, BSet &&bset3) 430 prop("lazy_or_then_indices_of<1>()", [](BSet &&bset1, BSet &&bset2, BSet &&bset3) {
431 stat(bset1);
432 stat(bset2);
433 stat(bset3);
434 auto result =
435 ContainerOf<StdSet>(BitVector::lazy_or_then_indices_of<1>(bset1.Bits, bset2.Bits, bset3.Bits));
436 auto size = std::min(std::min(bset1.Bits.size(), bset2.Bits.size()), bset3.Bits.size());
437 auto universum = Universum(size);
438 auto set_result = SetIntersection(universum, SetUnion(bset1.Indices, bset2.Indices, bset3.Indices));
439 RC_ASSERT(result == set_result);
440 });
__anonea1bced32402(BSet &&bset1, BSet &&bset2, BSet &&bset3) 441 prop("lazy_or_then_indices_of<0>()", [](BSet &&bset1, BSet &&bset2, BSet &&bset3) {
442 stat(bset1);
443 stat(bset2);
444 stat(bset3);
445 auto result =
446 ContainerOf<StdSet>(BitVector::lazy_or_then_indices_of<0>(bset1.Bits, bset2.Bits, bset3.Bits));
447 auto size = std::min(std::min(bset1.Bits.size(), bset2.Bits.size()), bset3.Bits.size());
448 auto universum = Universum(size);
449 auto set_result = SetDifference(universum, SetUnion(bset1.Indices, bset2.Indices, bset3.Indices));
450 RC_ASSERT(result == set_result);
451 });
__anonea1bced32502(BSet &&bset1, BSet &&bset2, BSet &&bset3) 452 prop("lazy_xor_then_indices_of<1>()", [](BSet &&bset1, BSet &&bset2, BSet &&bset3) {
453 stat(bset1);
454 stat(bset2);
455 stat(bset3);
456 auto result =
457 ContainerOf<StdSet>(BitVector::lazy_xor_then_indices_of<1>(bset1.Bits, bset2.Bits, bset3.Bits));
458 auto size = std::min(std::min(bset1.Bits.size(), bset2.Bits.size()), bset3.Bits.size());
459 auto universum = Universum(size);
460 auto xor1 =
461 SetDifference(SetUnion(bset1.Indices, bset2.Indices), SetIntersection(bset1.Indices, bset2.Indices));
462 auto xor2 = SetDifference(SetUnion(xor1, bset3.Indices), SetIntersection(xor1, bset3.Indices));
463 auto set_result = SetIntersection(universum, xor2);
464 RC_ASSERT(result == set_result);
465 });
__anonea1bced32602(BSet &&bset1, BSet &&bset2, BSet &&bset3) 466 prop("lazy_xor_then_indices_of<0>()", [](BSet &&bset1, BSet &&bset2, BSet &&bset3) {
467 stat(bset1);
468 stat(bset2);
469 stat(bset3);
470 auto result =
471 ContainerOf<StdSet>(BitVector::lazy_xor_then_indices_of<0>(bset1.Bits, bset2.Bits, bset3.Bits));
472 auto size = std::min(std::min(bset1.Bits.size(), bset2.Bits.size()), bset3.Bits.size());
473 auto universum = Universum(size);
474 auto xor1 =
475 SetDifference(SetUnion(bset1.Indices, bset2.Indices), SetIntersection(bset1.Indices, bset2.Indices));
476 auto xor2 = SetDifference(SetUnion(xor1, bset3.Indices), SetIntersection(xor1, bset3.Indices));
477 auto set_result = SetDifference(universum, xor2);
478 RC_ASSERT(result == set_result);
479 });
__anonea1bced32702(BSet &&bset1, BSet &&bset2, BSet &&bset3) 480 prop("lazy_and_not_then_indices_of<1>()", [](BSet &&bset1, BSet &&bset2, BSet &&bset3) {
481 stat(bset1);
482 stat(bset2);
483 stat(bset3);
484 auto result =
485 ContainerOf<StdSet>(BitVector::lazy_and_not_then_indices_of<1>(bset1.Bits, bset2.Bits, bset3.Bits));
486 auto size = std::min(std::min(bset1.Bits.size(), bset2.Bits.size()), bset3.Bits.size());
487 auto universum = Universum(size);
488 auto set_and = SetIntersection(bset1.Indices, bset2.Indices);
489 auto set_not = SetDifference(universum, bset3.Indices);
490 auto set_result = SetIntersection(set_and, set_not);
491 RC_ASSERT(result == set_result);
492 });
__anonea1bced32802(BSet &&bset1, BSet &&bset2, BSet &&bset3) 493 prop("lazy_and_not_then_indices_of<0>()", [](BSet &&bset1, BSet &&bset2, BSet &&bset3) {
494 stat(bset1);
495 stat(bset2);
496 stat(bset3);
497 auto result =
498 ContainerOf<StdSet>(BitVector::lazy_and_not_then_indices_of<0>(bset1.Bits, bset2.Bits, bset3.Bits));
499 auto size = std::min(std::min(bset1.Bits.size(), bset2.Bits.size()), bset3.Bits.size());
500 auto universum = Universum(size);
501 auto set_and = SetIntersection(bset1.Indices, bset2.Indices);
502 auto set_not = SetDifference(universum, bset3.Indices);
503 auto set_result = SetDifference(universum, SetIntersection(set_and, set_not));
504 RC_ASSERT(result == set_result);
505 });
506 }
507 }
508
509 } // namespace panda::verifier::test
510
511 #endif // !PANDA_CATCH2
512