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 Index<size_t>(); 513 } 514 if (val) { 515 return ValLazyIndicesOf(idx, to, val); 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 Index<size_t>(); 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 lastWordPartiallyFilled = (Size() & POS_MASK) != 0; 535 if (SizeInWords() > 0) { 536 for (; pos < (SizeInWords() - (lastWordPartiallyFilled ? 1 : 0)); ++pos) { 537 result += static_cast<size_t>(ark::Popcount(data_[pos])); 538 } 539 } 540 if (lastWordPartiallyFilled) { 541 const Word mask = MaskUpToIndex(Size() & POS_MASK); 542 result += static_cast<size_t>(ark::Popcount(data_[pos] & mask)); 543 } 544 return result; 545 } 546 547 template <typename Op, typename Binop, typename... Args> PowerOfOpThenFold(Op op,Binop binop,const Args &...args)548 static size_t PowerOfOpThenFold(Op op, Binop binop, const Args &...args) 549 { 550 size_t result = 0; 551 552 size_t sz = NAry {[](size_t a, size_t b) { return std::min(a, b); }}(args.SizeInWords()...); 553 size_t size = NAry {[](size_t a, size_t b) { return std::min(a, b); }}(args.Size()...); 554 size_t numArgs = sizeof...(Args); 555 auto getProcessedWord = [&op, &binop, numArgs, &args...](size_t idx) { 556 size_t n = 0; 557 auto unop = [&n, numArgs, &op](Word val) { return op(val, n++, numArgs); }; 558 return NAry {binop}(std::tuple<std::decay_t<decltype(args.data_[idx])>...> {unop(args.data_[idx])...}); 559 }; 560 561 size_t pos = 0; 562 bool lastWordPartiallyFilled = (size & POS_MASK) != 0; 563 if (sz > 0) { 564 for (; pos < (sz - (lastWordPartiallyFilled ? 1 : 0)); ++pos) { 565 auto val = getProcessedWord(pos); 566 result += static_cast<size_t>(ark::Popcount(val)); 567 } 568 } 569 if (lastWordPartiallyFilled) { 570 const Word mask = MaskUpToIndex(size & POS_MASK); 571 result += static_cast<size_t>(ark::Popcount(getProcessedWord(pos) & mask)); 572 } 573 return result; 574 } 575 576 template <typename... Args> PowerOfAnd(const Args &...args)577 static size_t PowerOfAnd(const Args &...args) 578 { 579 return PowerOfOpThenFold([](Word val, size_t, size_t) { return val; }, 580 [](Word lhs, Word rhs) { return lhs & rhs; }, args...); 581 } 582 583 template <typename... Args> PowerOfOr(const Args &...args)584 static size_t PowerOfOr(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> PowerOfXor(const Args &...args)591 static size_t PowerOfXor(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> PowerOfAndNot(const Args &...args)598 static size_t PowerOfAndNot(const Args &...args) 599 { 600 return PowerOfOpThenFold([](Word val, size_t idx, size_t numArgs) { return (idx < numArgs - 1) ? val : ~val; }, 601 [](Word lhs, Word rhs) { return lhs & rhs; }, args...); 602 } 603 Size()604 size_t Size() const 605 { 606 return size_; 607 } 608 SizeInWords()609 size_t SizeInWords() const 610 { 611 return SizeInWordsFromSizeInBits(size_); 612 } 613 Resize(size_t sz)614 void Resize(size_t sz) 615 { 616 if (sz == 0) { 617 Deallocate(); 618 } else { 619 size_t newSizeInWords = SizeInWordsFromSizeInBits(sz); 620 size_t oldSizeInWords = SizeInWordsFromSizeInBits(size_); 621 if (oldSizeInWords != newSizeInWords) { 622 Allocator allocator; 623 Word *newData = allocator.allocate(newSizeInWords); 624 ASSERT(newData != nullptr); 625 size_t pos = 0; 626 for (; pos < std::min(oldSizeInWords, newSizeInWords); ++pos) { 627 newData[pos] = data_[pos]; 628 } 629 for (; pos < newSizeInWords; ++pos) { 630 newData[pos] = 0; 631 } 632 Deallocate(); 633 data_ = newData; 634 } 635 size_ = sz; 636 } 637 } 638 639 template <const int V, typename Op, typename BinOp, typename... Args> LazyOpThenFoldThenIndicesOf(Op op,BinOp binop,const Args &...args)640 static auto LazyOpThenFoldThenIndicesOf(Op op, BinOp binop, const Args &...args) 641 { 642 // NOLINTNEXTLINE(google-build-using-namespace) 643 using namespace ark::verifier; 644 size_t sz = NAry {[](size_t a, size_t b) { return std::min(a, b); }}(args.SizeInWords()...); 645 size_t size = NAry {[](size_t a, size_t b) { return std::min(a, b); }}(args.Size()...); 646 size_t numArgs = sizeof...(Args); 647 auto getProcessedWord = [op, binop, numArgs, &args...](size_t idx) { 648 size_t n = 0; 649 auto unop = [&n, numArgs, &op](Word val) { return op(val, n++, numArgs); }; 650 Word val = NAry {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 = getProcessedWord(pos++); 655 size_t idx = 0; 656 return [sz, size, pos, val, idx, getProcessedWord]() mutable -> Index<size_t> { 657 do { 658 if (idx >= size) { 659 return {}; 660 } 661 if (val) { 662 return ValLazyOpIndicesOf(idx, size, val); 663 } 664 while (val == 0 && pos < sz) { 665 val = getProcessedWord(pos++); 666 } 667 idx = (pos - 1) << POS_SHIFT; 668 if (pos >= sz && val == 0) { 669 return {}; 670 } 671 } while (true); 672 }; 673 } 674 675 template <const int V, typename... Args> LazyAndThenIndicesOf(const Args &...args)676 static auto LazyAndThenIndicesOf(const Args &...args) 677 { 678 return LazyOpThenFoldThenIndicesOf<V>([](Word val, size_t, size_t) { return val; }, 679 [](Word lhs, Word rhs) { return lhs & rhs; }, args...); 680 } 681 682 template <const int V, typename... Args> LazyOrThenIndicesOf(const Args &...args)683 static auto LazyOrThenIndicesOf(const Args &...args) 684 { 685 return LazyOpThenFoldThenIndicesOf<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> LazyXorThenIndicesOf(const Args &...args)690 static auto LazyXorThenIndicesOf(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> LazyAndNotThenIndicesOf(const Args &...args)697 static auto LazyAndNotThenIndicesOf(const Args &...args) 698 { 699 return LazyOpThenFoldThenIndicesOf<V>( 700 [](Word val, size_t idx, size_t numArgs) { 701 val = (idx < numArgs - 1) ? val : ~val; 702 return val; 703 }, 704 [](Word lhs, Word rhs) { return lhs & rhs; }, args...); 705 } 706 707 // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic,hicpp-signed-bitwise) 708 709 private: 710 size_t size_; 711 Word *data_ = nullptr; 712 CopyFrom(const BitVector & other)713 void CopyFrom(const BitVector &other) 714 { 715 size_ = other.size_; 716 size_t sizeInWords = other.SizeInWords(); 717 data_ = Allocator().allocate(sizeInWords); 718 std::copy_n(other.data_, sizeInWords, data_); 719 } 720 MoveFrom(BitVector && other)721 void MoveFrom(BitVector &&other) noexcept 722 { 723 size_ = other.size_; 724 data_ = other.data_; 725 // don't rhs.Deallocate() as we stole its data_! 726 other.size_ = 0; 727 other.data_ = nullptr; 728 } 729 ValLazyIndicesOf(size_t & idx,size_t & to,Word & val)730 static Index<size_t> ValLazyIndicesOf(size_t &idx, size_t &to, Word &val) 731 { 732 auto i = static_cast<size_t>(ark::Ctz(val)); 733 idx += i; 734 if (idx > to) { 735 return {}; 736 } 737 val >>= i; 738 val >>= 1U; 739 return idx++; 740 } 741 ValLazyOpIndicesOf(size_t & idx,size_t & size,Word & val)742 static Index<size_t> ValLazyOpIndicesOf(size_t &idx, size_t &size, Word &val) 743 { 744 auto i = static_cast<size_t>(ark::Ctz(val)); 745 idx += i; 746 if (idx >= size) { 747 return {}; 748 } 749 val >>= i; 750 val >>= 1U; 751 return idx++; 752 } 753 }; 754 755 } // namespace ark::verifier 756 757 #endif // !PANDA_VERIFIER_BIT_VECTOR_HPP_ 758