• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef PANDA_VERIFIER_BIT_VECTOR_HPP_
17 #define PANDA_VERIFIER_BIT_VECTOR_HPP_
18 
19 #include "utils/bit_utils.h"
20 #include "function_traits.h"
21 #include "panda_or_std.h"
22 #include "macros.h"
23 #include "index.h"
24 
25 #include <utility>
26 #include <cstdint>
27 #include <limits>
28 #include <type_traits>
29 #include <cstddef>
30 #include <algorithm>
31 #include <tuple>
32 #include <iostream>
33 
34 namespace panda::verifier {
35 
36 #ifdef PANDA_TARGET_64
37 using Word = uint64_t;
38 #else
39 using Word = uint32_t;
40 #endif
41 
42 template <typename GetFunc>
43 class ConstBits {
44 public:
ConstBits(GetFunc && f)45     ConstBits(GetFunc &&f) : GetF_ {std::move(f)} {}
46     ~ConstBits() = default;
47     ConstBits() = delete;
48     ConstBits(const ConstBits &) = delete;
49     ConstBits(ConstBits &&) = default;
50     ConstBits &operator=(const ConstBits &) = delete;
51     ConstBits &operator=(ConstBits &&) = default;
52 
Word()53     operator Word() const
54     {
55         return GetF_();
56     }
57 
58     template <typename Rhs>
59     bool operator==(const Rhs &rhs) const
60     {
61         return GetF_() == rhs.GetF_();
62     }
63 
64 private:
65     GetFunc GetF_;
66     template <typename A>
67     friend class ConstBits;
68 };
69 
70 template <typename GetFunc, typename SetFunc>
71 class Bits : public ConstBits<GetFunc> {
72 public:
Bits(GetFunc && get,SetFunc && set)73     Bits(GetFunc &&get, SetFunc &&set) : ConstBits<GetFunc>(std::move(get)), SetF_ {std::move(set)} {}
74     ~Bits() = default;
75     Bits() = delete;
76     Bits(const Bits &) = delete;
77     Bits(Bits &&) = default;
78     Bits &operator=(const Bits &rhs)
79     {
80         SetF_(rhs);
81         return *this;
82     }
83     Bits &operator=(Bits &&) = default;
84 
85     Bits &operator=(Word val)
86     {
87         SetF_(val);
88         return *this;
89     }
90 
91 private:
92     SetFunc SetF_;
93 };
94 
95 class BitVector {
96     using Allocator = MPandaAllocator<Word>;
97     static constexpr size_t BITS_IN_WORD = sizeof(Word) * 8;
98     static constexpr size_t BITS_IN_INT = sizeof(int) * 8;
MAX_BIT_IDX()99     size_t MAX_BIT_IDX() const
100     {
101         return size_ - 1;
102     }
103     static constexpr size_t POS_SHIFT = panda::Ctz(BITS_IN_WORD);
104     static constexpr size_t POS_MASK = BITS_IN_WORD - 1;
105     static constexpr Word MAX_WORD = std::numeric_limits<Word>::max();
106 
MaskForIndex(size_t idx)107     static Word MaskForIndex(size_t idx)
108     {
109         return static_cast<Word>(1) << idx;
110     }
111 
MaskUpToIndex(size_t idx)112     static Word MaskUpToIndex(size_t idx)
113     {
114         return idx >= BITS_IN_WORD ? MAX_WORD : ((static_cast<Word>(1) << idx) - 1);
115     }
116 
117     class Bit {
118     public:
Bit(BitVector & bit_vector,size_t index)119         Bit(BitVector &bit_vector, size_t index) : bit_vector_ {bit_vector}, index_ {index} {};
120 
121         operator bool() const
122         {
123             return const_cast<const BitVector &>(bit_vector_)[index_];
124         }
125 
126         Bit &operator=(bool value)
127         {
128             if (value) {
129                 bit_vector_.Set(index_);
130             } else {
131                 bit_vector_.Clr(index_);
132             }
133             return *this;
134         }
135 
136     private:
137         BitVector &bit_vector_;
138         size_t index_;
139     };
140 
SizeInBitsFromSizeInWords(size_t size)141     static constexpr size_t SizeInBitsFromSizeInWords(size_t size)
142     {
143         return size << POS_SHIFT;
144     }
145 
SizeInWordsFromSizeInBits(size_t size)146     static constexpr size_t SizeInWordsFromSizeInBits(size_t size)
147     {
148         return (size + POS_MASK) >> POS_SHIFT;
149     }
150 
Deallocate()151     void Deallocate()
152     {
153         if (data_ != nullptr) {
154             Allocator allocator;
155             allocator.deallocate(data_, size_in_words());
156         }
157         size_ = 0;
158         data_ = nullptr;
159     }
160 
161 public:
BitVector(size_t sz)162     BitVector(size_t sz) : size_ {sz}, data_ {Allocator().allocate(size_in_words())}
163     {
164         clr();
165     }
~BitVector()166     ~BitVector()
167     {
168         Deallocate();
169     }
170 
BitVector(const BitVector & other)171     BitVector(const BitVector &other)
172     {
173         CopyFrom(other);
174     }
175 
BitVector(BitVector && other)176     BitVector(BitVector &&other) noexcept
177     {
178         MoveFrom(std::move(other));
179     }
180 
181     BitVector &operator=(const BitVector &rhs)
182     {
183         Deallocate();
184         CopyFrom(rhs);
185         return *this;
186     }
187 
188     BitVector &operator=(BitVector &&rhs) noexcept
189     {
190         Deallocate();
191         MoveFrom(std::move(rhs));
192         return *this;
193     }
194 
bits(size_t from,size_t to)195     auto bits(size_t from, size_t to) const
196     {
197         ASSERT(data_ != nullptr);
198         ASSERT(from <= to);
199         ASSERT(to <= MAX_BIT_IDX());
200         ASSERT(to - from <= BITS_IN_WORD - 1);
201         const Word MASK = MaskUpToIndex(to - from + 1);
202         const size_t POS_FROM = from >> POS_SHIFT;
203         const size_t POS_TO = to >> POS_SHIFT;
204         const size_t IDX_FROM = from & POS_MASK;
205         return ConstBits([this, MASK, POS_FROM, POS_TO, IDX_FROM]() -> Word {
206             if (POS_FROM == POS_TO) {
207                 return (data_[POS_FROM] >> IDX_FROM) & MASK;
208             } else {
209                 Word data = (data_[POS_FROM] >> IDX_FROM) | (data_[POS_TO] << (BITS_IN_WORD - IDX_FROM));
210                 return data & MASK;
211             }
212         });
213     }
214 
bits(size_t from,size_t to)215     auto bits(size_t from, size_t to)
216     {
217         ASSERT(data_ != nullptr);
218         ASSERT(from <= to);
219         ASSERT(to <= MAX_BIT_IDX());
220         ASSERT(to - from <= BITS_IN_WORD - 1);
221         const Word MASK = MaskUpToIndex(to - from + 1);
222         const size_t POS_FROM = from >> POS_SHIFT;
223         const size_t POS_TO = to >> POS_SHIFT;
224         const size_t IDX_FROM = from & POS_MASK;
225         return Bits(
226             [this, MASK, POS_FROM, POS_TO, IDX_FROM]() -> Word {
227                 if (POS_FROM == POS_TO) {
228                     return (data_[POS_FROM] >> IDX_FROM) & MASK;
229                 } else {
230                     Word data = (data_[POS_FROM] >> IDX_FROM) | (data_[POS_TO] << (BITS_IN_WORD - IDX_FROM));
231                     return data & MASK;
232                 }
233             },
234             [this, MASK, POS_FROM, POS_TO, IDX_FROM](Word val) {
235                 const Word VAL = val & MASK;
236                 const auto LOW_MASK = MASK << IDX_FROM;
237                 const auto LOW_VAL = VAL << IDX_FROM;
238                 if (POS_FROM == POS_TO) {
239                     data_[POS_FROM] &= ~LOW_MASK;
240                     data_[POS_FROM] |= LOW_VAL;
241                 } else {
242                     const auto HIGH_SHIFT = BITS_IN_WORD - IDX_FROM;
243                     const auto HIGH_MASK = MASK >> HIGH_SHIFT;
244                     const auto HIGH_VAL = VAL >> HIGH_SHIFT;
245                     data_[POS_FROM] &= ~LOW_MASK;
246                     data_[POS_FROM] |= LOW_VAL;
247                     data_[POS_TO] &= ~HIGH_MASK;
248                     data_[POS_TO] |= HIGH_VAL;
249                 }
250             });
251     }
252 
253     bool operator[](size_t idx) const
254     {
255         ASSERT(idx < size());
256         return data_[idx >> POS_SHIFT] & MaskForIndex(idx % BITS_IN_WORD);
257     }
258     Bit operator[](size_t idx)
259     {
260         return {*this, idx};
261     }
262 
clr()263     void clr()
264     {
265         for (size_t pos = 0; pos < size_in_words(); ++pos) {
266             data_[pos] = 0;
267         }
268     }
set()269     void set()
270     {
271         for (size_t pos = 0; pos < size_in_words(); ++pos) {
272             data_[pos] = MAX_WORD;
273         }
274     }
invert()275     void invert()
276     {
277         for (size_t pos = 0; pos < size_in_words(); ++pos) {
278             data_[pos] = ~data_[pos];
279         }
280     }
Clr(size_t idx)281     void Clr(size_t idx)
282     {
283         ASSERT(idx < size());
284         data_[idx >> POS_SHIFT] &= ~MaskForIndex(idx % BITS_IN_WORD);
285     }
Set(size_t idx)286     void Set(size_t idx)
287     {
288         ASSERT(idx < size());
289         data_[idx >> POS_SHIFT] |= MaskForIndex(idx % BITS_IN_WORD);
290     }
invert(size_t idx)291     void invert(size_t idx)
292     {
293         operator[](idx) = !operator[](idx);
294     }
295 
296     BitVector operator~() const
297     {
298         BitVector result {*this};
299         result.invert();
300         return result;
301     }
302 
303     bool operator==(const BitVector &rhs) const
304     {
305         if (size() != rhs.size()) {
306             return false;
307         }
308         size_t last_word_partial_bits = size() % BITS_IN_WORD;
309         size_t num_full_words = size_in_words() - (last_word_partial_bits ? 1 : 0);
310         for (size_t pos = 0; pos < num_full_words; pos++) {
311             if (data_[pos] != rhs.data_[pos]) {
312                 return false;
313             }
314         }
315         if (last_word_partial_bits) {
316             size_t last_word_start = size() - last_word_partial_bits;
317             return bits(last_word_start, size() - 1) == rhs.bits(last_word_start, size() - 1);
318         }
319         return true;
320     }
321 
322     bool operator!=(const BitVector &rhs) const
323     {
324         return !(*this == rhs);
325     }
326 
327     template <typename Handler>
process(size_t from,size_t to,Handler handler)328     void process(size_t from, size_t to, Handler handler)
329     {
330         ASSERT(data_ != nullptr);
331         ASSERT(from <= to);
332         ASSERT(to <= MAX_BIT_IDX());
333         const size_t POS_FROM = from >> POS_SHIFT;
334         const size_t POS_TO = to >> POS_SHIFT;
335         const size_t IDX_FROM = from & POS_MASK;
336         const size_t IDX_TO = to & POS_MASK;
337         auto process_word = [this, &handler](size_t pos) {
338             const Word VAL = handler(data_[pos], BITS_IN_WORD);
339             data_[pos] = VAL;
340         };
341         auto process_part = [this, &handler, &process_word](size_t pos, size_t idx_from, size_t idx_to) {
342             const auto LEN = idx_to - idx_from + 1;
343             if (LEN == BITS_IN_WORD) {
344                 process_word(pos);
345             } else {
346                 const Word MASK = MaskUpToIndex(LEN);
347                 const Word VAL = handler((data_[pos] >> idx_from) & MASK, LEN) & MASK;
348                 data_[pos] &= ~(MASK << idx_from);
349                 data_[pos] |= VAL << idx_from;
350             }
351         };
352         if (POS_FROM == POS_TO) {
353             process_part(POS_FROM, IDX_FROM, IDX_TO);
354         } else {
355             process_part(POS_FROM, IDX_FROM, BITS_IN_WORD - 1);
356             for (size_t pos = POS_FROM + 1; pos < POS_TO; ++pos) {
357                 process_word(pos);
358             }
359             process_part(POS_TO, 0, IDX_TO);
360         }
361     }
362 
Clr(size_t from,size_t to)363     void Clr(size_t from, size_t to)
364     {
365         process(from, to, [](auto, auto) { return static_cast<Word>(0); });
366     }
367 
Set(size_t from,size_t to)368     void Set(size_t from, size_t to)
369     {
370         process(from, to, [](auto, auto) { return MAX_WORD; });
371     }
372 
invert(size_t from,size_t to)373     void invert(size_t from, size_t to)
374     {
375         process(from, to, [](auto val, auto) { return ~val; });
376     }
377 
378     template <typename Handler>
process(const BitVector & rhs,Handler && handler)379     void process(const BitVector &rhs,
380                  Handler &&handler)  // every handler result bit must depend only from corresponding bit pair
381     {
382         size_t sz = std::min(size(), rhs.size());
383         size_t words = SizeInWordsFromSizeInBits(sz);
384         size_t lhs_words = size_in_words();
385         size_t pos = 0;
386         for (; pos < words; ++pos) {
387             data_[pos] = handler(data_[pos], rhs.data_[pos]);
388         }
389         if ((pos >= lhs_words) || ((handler(0U, 0U) == 0U) && (handler(1U, 0U) == 1U))) {
390             return;
391         }
392         for (; pos < lhs_words; ++pos) {
393             data_[pos] = handler(data_[pos], 0U);
394         }
395     }
396 
397     BitVector &operator&=(const BitVector &rhs)
398     {
399         process(rhs, [](const auto l, const auto r) { return l & r; });
400         return *this;
401     }
402 
403     BitVector &operator|=(const BitVector &rhs)
404     {
405         if (size() < rhs.size()) {
406             resize(rhs.size());
407         }
408         process(rhs, [](const auto l, const auto r) { return l | r; });
409         return *this;
410     }
411 
412     BitVector &operator^=(const BitVector &rhs)
413     {
414         if (size() < rhs.size()) {
415             resize(rhs.size());
416         }
417         process(rhs, [](const auto l, const auto r) { return l ^ r; });
418         return *this;
419     }
420 
421     BitVector operator&(const BitVector &rhs) const
422     {
423         if (size() > rhs.size()) {
424             return rhs & *this;
425         }
426         BitVector result {*this};
427         result &= rhs;
428         return result;
429     }
430 
431     BitVector operator|(const BitVector &rhs) const
432     {
433         if (size() < rhs.size()) {
434             return rhs | *this;
435         }
436         BitVector result {*this};
437         result |= rhs;
438         return result;
439     }
440 
441     BitVector operator^(const BitVector &rhs) const
442     {
443         if (size() < rhs.size()) {
444             return rhs ^ *this;
445         }
446         BitVector result {*this};
447         result ^= rhs;
448         return result;
449     }
450 
451     template <typename Handler>
for_all_idx_val(Handler handler)452     void for_all_idx_val(Handler handler) const
453     {
454         size_t last_word_partial_bits = size() % BITS_IN_WORD;
455         size_t num_full_words = size_in_words() - (last_word_partial_bits ? 1 : 0);
456         for (size_t pos = 0; pos < num_full_words; pos++) {
457             Word val = data_[pos];
458             if (!handler(pos * BITS_IN_WORD, val)) {
459                 return;
460             }
461         }
462         if (last_word_partial_bits) {
463             size_t last_word_start = size() - last_word_partial_bits;
464             Word val = bits(last_word_start, size() - 1);
465             handler(last_word_start, val);
466         }
467     }
468 
469     template <const int Val, typename Handler>
for_all_idx_of(Handler handler)470     bool for_all_idx_of(Handler handler) const
471     {
472         for (size_t pos = 0; pos < size_in_words(); ++pos) {
473             auto val = data_[pos];
474             val = Val ? val : ~val;
475             size_t idx = pos << POS_SHIFT;
476             while (val) {
477                 auto i = static_cast<size_t>(panda::Ctz(val));
478                 idx += i;
479                 if (idx >= size()) {
480                     return true;
481                 }
482                 if (!handler(idx)) {
483                     return false;
484                 }
485                 ++idx;
486                 val >>= i;
487                 val >>= 1;
488             }
489         }
490         return true;
491     }
492 
493     template <const int Val>
494     auto LazyIndicesOf(size_t from = 0, size_t to = std::numeric_limits<size_t>::max()) const
495     {
496         size_t idx = from;
497         size_t pos = from >> POS_SHIFT;
498         auto val = (Val ? data_[pos] : ~data_[pos]) >> (idx % BITS_IN_WORD);
499         ++pos;
500         to = std::min(size_ - 1, to);
501         auto sz = SizeInWordsFromSizeInBits(to + 1);
502         return [this, sz, to, pos, val, idx]() mutable -> Index<size_t> {
503             while (true) {
504                 if (idx > to) {
505                     return {};
506                 }
507                 if (val) {
508                     auto i = static_cast<size_t>(panda::Ctz(val));
509                     idx += i;
510                     if (idx > to) {
511                         return {};
512                     }
513                     val >>= i;
514                     val >>= 1;
515                     return idx++;
516                 }
517                 while (val == 0 && pos < sz) {
518                     val = Val ? data_[pos] : ~data_[pos];
519                     ++pos;
520                 }
521                 idx = (pos - 1) << POS_SHIFT;
522                 if (pos >= sz && val == 0) {
523                     return {};
524                 }
525             }
526         };
527     }
528 
SetBitsCount()529     size_t SetBitsCount() const
530     {
531         size_t result = 0;
532 
533         size_t pos = 0;
534         bool last_word_partially_filled = ((size() & POS_MASK) == 0) ? false : true;
535         if (size_in_words() > 0) {
536             for (; pos < (size_in_words() - (last_word_partially_filled ? 1 : 0)); ++pos) {
537                 result += static_cast<size_t>(panda::Popcount(data_[pos]));
538             }
539         }
540         if (last_word_partially_filled) {
541             const Word MASK = MaskUpToIndex(size() & POS_MASK);
542             result += static_cast<size_t>(panda::Popcount(data_[pos] & MASK));
543         }
544         return result;
545     }
546 
547     template <typename Op, typename Binop, typename... Args>
power_of_op_then_fold(Op op,Binop binop,const Args &...args)548     static size_t power_of_op_then_fold(Op op, Binop binop, const Args &... args)
549     {
550         size_t result = 0;
551 
552         size_t sz = n_ary {[](size_t a, size_t b) { return std::min(a, b); }}(args.size_in_words()...);
553         size_t size = n_ary {[](size_t a, size_t b) { return std::min(a, b); }}(args.size()...);
554         size_t num_args = sizeof...(Args);
555         auto get_processed_word = [&op, &binop, num_args, &args...](size_t idx) {
556             size_t n = 0;
557             auto unop = [&n, num_args, &op](Word val) { return op(val, n++, num_args); };
558             return n_ary {binop}(std::tuple<std::decay_t<decltype(args.data_[idx])>...> {unop(args.data_[idx])...});
559         };
560 
561         size_t pos = 0;
562         bool last_word_partially_filled = ((size & POS_MASK) == 0) ? false : true;
563         if (sz > 0) {
564             for (; pos < (sz - (last_word_partially_filled ? 1 : 0)); ++pos) {
565                 auto val = get_processed_word(pos);
566                 result += static_cast<size_t>(panda::Popcount(val));
567             }
568         }
569         if (last_word_partially_filled) {
570             const Word MASK = MaskUpToIndex(size & POS_MASK);
571             result += static_cast<size_t>(panda::Popcount(get_processed_word(pos) & MASK));
572         }
573         return result;
574     }
575 
576     template <typename... Args>
power_of_and(const Args &...args)577     static size_t power_of_and(const Args &... args)
578     {
579         return power_of_op_then_fold([](Word val, size_t, size_t) { return val; },
580                                      [](Word lhs, Word rhs) { return lhs & rhs; }, args...);
581     }
582 
583     template <typename... Args>
power_of_or(const Args &...args)584     static size_t power_of_or(const Args &... args)
585     {
586         return power_of_op_then_fold([](Word val, size_t, size_t) { return val; },
587                                      [](Word lhs, Word rhs) { return lhs | rhs; }, args...);
588     }
589 
590     template <typename... Args>
power_of_xor(const Args &...args)591     static size_t power_of_xor(const Args &... args)
592     {
593         return power_of_op_then_fold([](Word val, size_t, size_t) { return val; },
594                                      [](Word lhs, Word rhs) { return lhs ^ rhs; }, args...);
595     }
596 
597     template <typename... Args>
power_of_and_not(const Args &...args)598     static size_t power_of_and_not(const Args &... args)
599     {
600         return power_of_op_then_fold(
601             [](Word val, size_t idx, size_t num_args) { return (idx < num_args - 1) ? val : ~val; },
602             [](Word lhs, Word rhs) { return lhs & rhs; }, args...);
603     }
604 
size()605     size_t size() const
606     {
607         return size_;
608     }
609 
size_in_words()610     size_t size_in_words() const
611     {
612         return SizeInWordsFromSizeInBits(size_);
613     }
614 
resize(size_t sz)615     void resize(size_t sz)
616     {
617         if (sz == 0) {
618             Deallocate();
619         } else {
620             size_t new_size_in_words = SizeInWordsFromSizeInBits(sz);
621             size_t old_size_in_words = SizeInWordsFromSizeInBits(size_);
622             if (old_size_in_words != new_size_in_words) {
623                 Allocator allocator;
624                 Word *new_data = allocator.allocate(new_size_in_words);
625                 ASSERT(new_data != nullptr);
626                 size_t pos = 0;
627                 for (; pos < std::min(old_size_in_words, new_size_in_words); ++pos) {
628                     new_data[pos] = data_[pos];
629                 }
630                 for (; pos < new_size_in_words; ++pos) {
631                     new_data[pos] = 0;
632                 }
633                 Deallocate();
634                 data_ = new_data;
635             }
636             size_ = sz;
637         }
638     }
639 
640     template <const int V, typename Op, typename BinOp, typename... Args>
lazy_op_then_fold_then_indices_of(Op op,BinOp binop,const Args &...args)641     static auto lazy_op_then_fold_then_indices_of(Op op, BinOp binop, const Args &... args)
642     {
643         using namespace panda::verifier;
644         size_t sz = n_ary {[](size_t a, size_t b) { return std::min(a, b); }}(args.size_in_words()...);
645         size_t size = n_ary {[](size_t a, size_t b) { return std::min(a, b); }}(args.size()...);
646         size_t num_args = sizeof...(Args);
647         auto get_processed_word = [op, binop, num_args, &args...](size_t idx) {
648             size_t n = 0;
649             auto unop = [&n, num_args, &op](Word val) { return op(val, n++, num_args); };
650             Word val = n_ary {binop}(std::tuple<std::decay_t<decltype(args.data_[idx])>...> {unop(args.data_[idx])...});
651             return V ? val : ~val;
652         };
653         size_t pos = 0;
654         auto val = get_processed_word(pos++);
655         size_t idx = 0;
656         return [sz, size, pos, val, idx, get_processed_word]() mutable -> Index<size_t> {
657             do {
658                 if (idx >= size) {
659                     return {};
660                 }
661                 if (val) {
662                     auto i = static_cast<size_t>(panda::Ctz(val));
663                     idx += i;
664                     if (idx >= size) {
665                         return {};
666                     }
667                     val >>= i;
668                     val >>= 1;
669                     return idx++;
670                 }
671                 while (val == 0 && pos < sz) {
672                     val = get_processed_word(pos++);
673                 }
674                 idx = (pos - 1) << POS_SHIFT;
675                 if (pos >= sz && val == 0) {
676                     return {};
677                 }
678             } while (true);
679         };
680     }
681 
682     template <const int V, typename... Args>
lazy_and_then_indices_of(const Args &...args)683     static auto lazy_and_then_indices_of(const Args &... args)
684     {
685         return lazy_op_then_fold_then_indices_of<V>([](Word val, size_t, size_t) { return val; },
686                                                     [](Word lhs, Word rhs) { return lhs & rhs; }, args...);
687     }
688 
689     template <const int V, typename... Args>
lazy_or_then_indices_of(const Args &...args)690     static auto lazy_or_then_indices_of(const Args &... args)
691     {
692         return lazy_op_then_fold_then_indices_of<V>([](Word val, size_t, size_t) { return val; },
693                                                     [](Word lhs, Word rhs) { return lhs | rhs; }, args...);
694     }
695 
696     template <const int V, typename... Args>
lazy_xor_then_indices_of(const Args &...args)697     static auto lazy_xor_then_indices_of(const Args &... args)
698     {
699         return lazy_op_then_fold_then_indices_of<V>([](Word val, size_t, size_t) { return val; },
700                                                     [](Word lhs, Word rhs) { return lhs ^ rhs; }, args...);
701     }
702 
703     template <const int V, typename... Args>
lazy_and_not_then_indices_of(const Args &...args)704     static auto lazy_and_not_then_indices_of(const Args &... args)
705     {
706         return lazy_op_then_fold_then_indices_of<V>(
707             [](Word val, size_t idx, size_t num_args) {
708                 val = (idx < num_args - 1) ? val : ~val;
709                 return val;
710             },
711             [](Word lhs, Word rhs) { return lhs & rhs; }, args...);
712     }
713 
714 private:
715     size_t size_;
716     Word *data_ = nullptr;
717 
CopyFrom(const BitVector & other)718     void CopyFrom(const BitVector &other)
719     {
720         size_ = other.size_;
721         size_t size_in_words = other.size_in_words();
722         data_ = Allocator().allocate(size_in_words);
723         std::copy_n(other.data_, size_in_words, data_);
724     }
725 
MoveFrom(BitVector && other)726     void MoveFrom(BitVector &&other) noexcept
727     {
728         size_ = other.size_;
729         data_ = other.data_;
730         // don't rhs.Deallocate() as we stole its data_!
731         other.size_ = 0;
732         other.data_ = nullptr;
733     }
734 };
735 
736 }  // namespace panda::verifier
737 
738 #endif  // !PANDA_VERIFIER_BIT_VECTOR_HPP_
739