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