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