1 /* 2 * Copyright (c) 2021 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_VERIFICATION_UTIL_INT_SET_H_ 17 #define PANDA_VERIFICATION_UTIL_INT_SET_H_ 18 19 #include "bit_vector.h" 20 21 #include <iterator> 22 23 namespace panda::verifier { 24 25 /** 26 * @brief A set implementation for integral types which automatically switches between representations 27 * (e.g. std::unordered_set or a sorted vector for small sets, bitvector for large sets). 28 * 29 * @tparam T Element type 30 * @tparam THRESHOLD threshold for switching between representations 31 */ 32 template <typename T, size_t THRESHOLD = 256> 33 class IntSet { 34 // need forward references to allow use of private classes in public method implementations 35 // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_CLASSSCOPE_ORDER) 36 private: 37 class ConstIterRepr; 38 class SmallConstIterRepr; 39 template <typename Stream> 40 class LargeConstIterRepr; 41 42 public: IntSet()43 IntSet() : repr_ {MMakePandaUnique<SmallRepr>()} {}; 44 ~IntSet() = default; 45 DEFAULT_MOVE_SEMANTIC(IntSet); 46 IntSet(const IntSet & other)47 IntSet(const IntSet &other) : repr_ {other.repr_->Clone()} {}; 48 IntSet &operator=(const IntSet &other) 49 { 50 repr_ = other.repr_->Clone(); 51 return *this; 52 } 53 Contains(T x)54 bool Contains(T x) const 55 { 56 return repr_->Contains(x); 57 } 58 Size()59 size_t Size() const 60 { 61 return repr_->Size(); 62 } 63 Insert(T x)64 void Insert(T x) 65 { 66 repr_->Insert(x); 67 if (UNLIKELY(Size() == THRESHOLD && repr_->Type() == ReprType::SMALL)) { 68 MoveToLargeRepr(); 69 } 70 } 71 72 template <bool known_to_be_sorted = false, typename Iter> Insert(Iter begin,Iter end)73 void Insert(Iter begin, Iter end) 74 { 75 switch (repr_->Type()) { 76 case ReprType::SMALL: 77 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_HORIZON_SPACE) 78 AsSmallRepr().template InsertManyImpl<known_to_be_sorted>(begin, end); 79 if (UNLIKELY(Size() >= THRESHOLD)) { 80 MoveToLargeRepr(); 81 if (begin != end) { 82 // if we get here, repr is large now and there are remaining elements 83 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_HORIZON_SPACE) 84 AsLargeRepr().template InsertManyImpl<known_to_be_sorted>(std::move(begin), std::move(end)); 85 } 86 } 87 return; 88 case ReprType::LARGE: 89 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_HORIZON_SPACE) 90 AsLargeRepr().template InsertManyImpl<known_to_be_sorted>(std::move(begin), std::move(end)); 91 return; 92 default: 93 UNREACHABLE(); 94 } 95 } 96 97 template <size_t THRESHOLD2> 98 IntSet<T, THRESHOLD> operator&(const IntSet<T, THRESHOLD2> &other) const 99 { 100 return other.SwitchOnRepr([this](const auto &other_repr) { return repr_->Intersect(other_repr); }); 101 } 102 103 template <size_t THRESHOLD2> 104 IntSet<T, THRESHOLD> &operator&=(const IntSet<T, THRESHOLD2> &other) 105 { 106 if (repr_->Type() == ReprType::LARGE && other.repr_->Type() == ReprType::SMALL) { 107 *this = other & *this; 108 } else { 109 bool change_repr = 110 other.SwitchOnRepr([this](const auto &other_repr) { return repr_->IntersectInPlace(other_repr); }); 111 if (change_repr) { 112 MoveToSmallRepr(); 113 } 114 } 115 return *this; 116 } 117 118 template <size_t THRESHOLD2> 119 IntSet<T, THRESHOLD> operator|(const IntSet<T, THRESHOLD2> &other) const 120 { 121 return other.SwitchOnRepr([this](const auto &other_repr) { return repr_->Union(other_repr); }); 122 } 123 124 template <size_t THRESHOLD2> 125 IntSet<T, THRESHOLD> &operator|=(const IntSet<T, THRESHOLD2> &other) 126 { 127 if (other.repr_->Type() == ReprType::SMALL) { 128 const auto &other_repr = other.AsSmallRepr().repr_; 129 Insert<true>(other_repr.cbegin(), other_repr.cend()); 130 } else { 131 if (repr_->Type() == ReprType::SMALL) { 132 *this = other | *this; 133 } else { 134 AsLargeRepr().UnionInPlace(other.AsLargeRepr()); 135 } 136 } 137 return *this; 138 } 139 140 // Returns a lambda repeated calls to which return ordered values of the intersection 141 template <size_t THRESHOLD2> LazyIntersect(const IntSet<T,THRESHOLD2> & other)142 auto LazyIntersect(const IntSet<T, THRESHOLD2> &other) const 143 { 144 auto &&stream1 = AsStream(); 145 auto &&stream2 = other.AsStream(); 146 return [val1 = stream1(), val2 = stream2(), stream1 = std::move(stream1), 147 stream2 = std::move(stream2)]() mutable -> Index<T> { 148 while (val1.IsValid() && val2.IsValid()) { 149 if (val1 < val2) { 150 val1 = stream1(); 151 } else if (val1 > val2) { 152 val2 = stream2(); 153 } else { 154 auto tmp = val1; 155 val1 = stream1(); 156 val2 = stream2(); 157 return tmp; 158 } 159 } 160 return {}; 161 }; 162 } 163 164 template <typename Handler> ForAll(Handler && handler)165 bool ForAll(Handler &&handler) const 166 { 167 return SwitchOnRepr([handler = std::move(handler)](const auto &repr) { return repr.ForAll(handler); }); 168 } 169 AsStream()170 std::function<Index<T>()> AsStream() const 171 { 172 return SwitchOnRepr([](const auto &repr) { return std::function<Index<T>()>(repr.AsStream()); }); 173 } 174 175 class const_iterator { 176 public: 177 using iterator_category = std::input_iterator_tag; 178 using value_type = T; 179 using reference = T; 180 using pointer = T *; 181 using difference_type = void; 182 const_iterator(typename MPandaVector<T>::const_iterator i)183 const_iterator(typename MPandaVector<T>::const_iterator i) : repr_ {MMakePandaUnique<SmallConstIterRepr>(i)} {}; 184 ~const_iterator() = default; 185 // should be a constructor, but GCC can't handle it properly 186 template <typename Stream> make(Stream && stream,Index<T> index)187 static const_iterator make(Stream &&stream, Index<T> index) 188 { 189 return {MMakePandaUnique<LargeConstIterRepr<Stream>>(std::move(stream), index)}; 190 } 191 const_iterator(const const_iterator & other)192 const_iterator(const const_iterator &other) : repr_ {other.repr_->Clone()} {}; 193 const_iterator &operator=(const const_iterator &other) 194 { 195 repr_ = other.repr_->Clone(); 196 return *this; 197 } 198 199 T operator*() const 200 { 201 return repr_->Deref(); 202 } 203 204 const_iterator &operator++() 205 { 206 repr_->Increment(); 207 return *this; 208 } 209 210 const_iterator operator++(int) 211 { 212 const_iterator tmp(repr_->Clone()); 213 this->operator++(); 214 return tmp; 215 } 216 217 friend bool operator==(const const_iterator &a, const const_iterator &b) 218 { 219 const auto &a_repr = *(a.repr_.get()); 220 const auto &b_repr = *(b.repr_.get()); 221 return a_repr.Type() == b_repr.Type() && a_repr.Equals(b_repr); 222 }; 223 224 friend bool operator!=(const const_iterator &a, const const_iterator &b) 225 { 226 return !(a == b); 227 }; 228 229 private: 230 MPandaUniquePtr<ConstIterRepr> repr_; 231 const_iterator(MPandaUniquePtr<ConstIterRepr> && repr)232 const_iterator(MPandaUniquePtr<ConstIterRepr> &&repr) : repr_ {std::move(repr)} {}; 233 234 friend class IntSet; 235 }; 236 237 using iterator = const_iterator; 238 begin()239 iterator begin() 240 { 241 return const_cast<const IntSet<T, THRESHOLD> *>(this)->cbegin(); 242 } 243 end()244 iterator end() 245 { 246 return const_cast<const IntSet<T, THRESHOLD> *>(this)->cend(); 247 } 248 begin()249 const_iterator begin() const 250 { 251 return cbegin(); 252 } 253 end()254 const_iterator end() const 255 { 256 return cend(); 257 } 258 cbegin()259 const_iterator cbegin() const 260 { 261 return repr_->cbegin(); 262 } 263 cend()264 const_iterator cend() const 265 { 266 return repr_->cend(); 267 } 268 269 template <size_t THRESHOLD2> 270 bool operator==(const IntSet<T, THRESHOLD2> &rhs) const 271 { 272 ReprType lhs_type = repr_->Type(); 273 ReprType rhs_type = rhs.repr_->Type(); 274 if (lhs_type == ReprType::SMALL && rhs_type == ReprType::SMALL) { 275 return AsSmallRepr().repr_ == rhs.AsSmallRepr().repr_; 276 } else if (lhs_type == ReprType::LARGE && rhs_type == ReprType::LARGE) { 277 return AsLargeRepr().repr_ == rhs.AsLargeRepr().repr_; 278 } else { 279 if (Size() != rhs.Size()) { 280 return false; 281 } 282 auto lhs_stream {AsStream()}; 283 auto rhs_stream {rhs.AsStream()}; 284 auto lhs_val {lhs_stream()}; 285 auto rhs_val {rhs_stream()}; 286 while (lhs_val.IsValid() && rhs_val.IsValid()) { 287 if (lhs_val != rhs_val) { 288 return false; 289 } 290 lhs_val = lhs_stream(); 291 rhs_val = rhs_stream(); 292 } 293 return lhs_val == rhs_val; 294 } 295 } 296 297 template <size_t THRESHOLD2> 298 bool operator!=(const IntSet<T, THRESHOLD2> &rhs) const 299 { 300 return !(*this == rhs); 301 } 302 303 private: 304 enum class ReprType { SMALL, LARGE }; 305 306 class SmallRepr; 307 class LargeRepr; 308 309 class Repr { 310 public: 311 virtual ReprType Type() const = 0; 312 virtual bool Contains(T x) const = 0; 313 virtual void Insert(T x) = 0; 314 virtual size_t Size() const = 0; 315 virtual IntSet<T, THRESHOLD> Intersect(const SmallRepr &other) const = 0; 316 virtual IntSet<T, THRESHOLD> Intersect(const LargeRepr &other) const = 0; 317 // returns true if repr should be changed (from Large to Small) 318 virtual bool IntersectInPlace(const SmallRepr &other) = 0; 319 virtual bool IntersectInPlace(const LargeRepr &other) = 0; 320 virtual IntSet<T, THRESHOLD> Union(const SmallRepr &other) const = 0; 321 virtual IntSet<T, THRESHOLD> Union(const LargeRepr &other) const = 0; 322 virtual MPandaUniquePtr<Repr> Clone() const = 0; 323 virtual const_iterator cbegin() const = 0; 324 virtual const_iterator cend() const = 0; 325 virtual ~Repr() = default; 326 begin()327 iterator begin() 328 { 329 return const_cast<const Repr *>(this)->cbegin(); 330 } 331 end()332 iterator end() 333 { 334 return const_cast<const Repr *>(this)->cend(); 335 } 336 begin()337 const_iterator begin() const 338 { 339 return cbegin(); 340 } 341 end()342 const_iterator end() const 343 { 344 return cend(); 345 } 346 }; 347 348 class SmallRepr final : public Repr { 349 public: 350 SmallRepr() = default; SmallRepr(MPandaVector<T> set)351 SmallRepr(MPandaVector<T> set) : repr_ {set} {}; 352 ~SmallRepr() = default; 353 Type()354 ReprType Type() const override 355 { 356 return ReprType::SMALL; 357 } 358 Contains(T x)359 bool Contains(T x) const override 360 { 361 return std::binary_search(repr_.begin(), repr_.end(), x); 362 } 363 Insert(T x)364 void Insert(T x) override 365 { 366 Insert(x, 0); 367 } 368 Size()369 size_t Size() const override 370 { 371 return repr_.size(); 372 } 373 Intersect(const SmallRepr & other)374 IntSet<T, THRESHOLD> Intersect(const SmallRepr &other) const override 375 { 376 if (other.Size() < Size()) { 377 return other.Intersect(*this); 378 } else { 379 MPandaVector<T> result; 380 std::set_intersection(repr_.begin(), repr_.end(), other.repr_.begin(), other.repr_.end(), 381 std::back_inserter(result)); 382 return {result}; 383 } 384 } 385 Intersect(const LargeRepr & other)386 IntSet<T, THRESHOLD> Intersect(const LargeRepr &other) const override 387 { 388 MPandaVector<T> result; 389 for (T value : repr_) { 390 if (other.Contains(value)) { 391 result.push_back(value); 392 } 393 } 394 return {result}; 395 } 396 IntersectInPlace(const SmallRepr & other)397 bool IntersectInPlace(const SmallRepr &other) override 398 { 399 repr_.erase( 400 std::remove_if(repr_.begin(), repr_.end(), 401 [&, other_iter = other.repr_.begin(), other_end = other.repr_.end()](T x) mutable { 402 other_iter = std::lower_bound(other_iter, other_end, x); 403 return other_iter == other_end || *other_iter != x; 404 }), 405 repr_.end()); 406 return false; 407 } 408 IntersectInPlace(const LargeRepr & other)409 bool IntersectInPlace(const LargeRepr &other) override 410 { 411 repr_.erase(std::remove_if(repr_.begin(), repr_.end(), [&](T x) { return !other.Contains(x); }), 412 repr_.end()); 413 return false; 414 } 415 Union(const SmallRepr & other)416 IntSet<T, THRESHOLD> Union(const SmallRepr &other) const override 417 { 418 MPandaVector<T> result; 419 std::set_union(repr_.begin(), repr_.end(), other.repr_.begin(), other.repr_.end(), 420 std::back_inserter(result)); 421 if (result.size() < THRESHOLD) { 422 return result; 423 } else { 424 return VectorToBitVector(result); 425 } 426 } 427 Union(const LargeRepr & other)428 IntSet<T, THRESHOLD> Union(const LargeRepr &other) const override 429 { 430 return other.Union(*this); 431 } 432 Clone()433 MPandaUniquePtr<Repr> Clone() const override 434 { 435 return MMakePandaUnique<SmallRepr>(repr_); 436 } 437 cbegin()438 const_iterator cbegin() const override 439 { 440 return {repr_.cbegin()}; 441 } 442 cend()443 const_iterator cend() const override 444 { 445 return {repr_.cend()}; 446 } 447 MaxElem()448 T MaxElem() const 449 { 450 return *repr_.rbegin(); 451 } 452 453 template <bool known_to_be_sorted, typename Iter> InsertManyImpl(Iter & begin,const Iter & end)454 void InsertManyImpl(Iter &begin, const Iter &end) 455 { 456 size_t sz = Size(); 457 size_t lower_bound = 0; 458 while (sz < THRESHOLD) { 459 for (size_t i = sz; i < THRESHOLD; i++) { 460 if (begin == end) { 461 return; 462 } 463 if (known_to_be_sorted) { 464 lower_bound = Insert(*begin, lower_bound); 465 } else { 466 Insert(*begin, 0); 467 } 468 ++begin; 469 } 470 sz = Size(); 471 } 472 } 473 474 template <typename Handler> ForAll(Handler && handler)475 bool ForAll(Handler &&handler) const 476 { 477 for (T value : repr_) { 478 if (!handler(value)) { 479 return false; 480 } 481 } 482 return true; 483 } 484 AsStream()485 auto AsStream() const 486 { 487 return [i = size_t(0), this]() mutable -> Index<T> { 488 if (i < repr_.size()) { 489 return repr_[i++]; 490 } else { 491 return {}; 492 } 493 }; 494 } 495 496 private: Insert(T x,size_t lower_bound)497 size_t Insert(T x, size_t lower_bound) 498 { 499 auto iter = std::lower_bound(repr_.begin() + lower_bound, repr_.end(), x); 500 size_t new_lower_bound = iter - repr_.begin(); 501 if (iter == repr_.end()) { 502 repr_.push_back(x); 503 } else if (*iter != x) { 504 repr_.insert(iter, x); 505 } 506 return new_lower_bound; 507 } 508 509 MPandaVector<T> repr_; 510 friend class IntSet; 511 }; 512 513 class LargeRepr final : public Repr { 514 public: LargeRepr(BitVector set)515 LargeRepr(BitVector set) : repr_ {set} {}; 516 ~LargeRepr() = default; 517 Type()518 ReprType Type() const override 519 { 520 return ReprType::LARGE; 521 } 522 Contains(T x)523 bool Contains(T x) const override 524 { 525 return x < repr_.size() && repr_[x]; 526 } 527 Insert(T x)528 void Insert(T x) override 529 { 530 if (x >= repr_.size()) { 531 repr_.resize(x * 3U / 2U); 532 } 533 repr_.Set(x); 534 } 535 Size()536 size_t Size() const override 537 { 538 return repr_.SetBitsCount(); 539 } 540 Intersect(const SmallRepr & other)541 IntSet<T, THRESHOLD> Intersect(const SmallRepr &other) const override 542 { 543 return other.Intersect(*this); 544 } 545 Intersect(const LargeRepr & other)546 IntSet<T, THRESHOLD> Intersect(const LargeRepr &other) const override 547 { 548 BitVector res = repr_ & other.repr_; 549 if (res.SetBitsCount() >= THRESHOLD) { 550 return res; 551 } else { 552 return BitVectorToVector(res); 553 } 554 } 555 IntersectInPlace(const SmallRepr & other)556 bool IntersectInPlace(const SmallRepr &other) override 557 { 558 if (other.Size() == 0) { 559 repr_ = BitVector(0); 560 } else { 561 size_t other_bv_size = other.MaxElem() + 1; 562 BitVector bv(other_bv_size); 563 for (T x : other.repr_) { 564 bv.Set(x); 565 } 566 ResizeDownOnly(other_bv_size); 567 repr_ &= bv; 568 } 569 return true; 570 } 571 IntersectInPlace(const LargeRepr & other)572 bool IntersectInPlace(const LargeRepr &other) override 573 { 574 ResizeDownOnly(other.repr_.size()); 575 repr_ &= other.repr_; 576 return Size() < THRESHOLD; 577 } 578 Union(const SmallRepr & other)579 IntSet<T, THRESHOLD> Union(const SmallRepr &other) const override 580 { 581 IntSet<T, THRESHOLD> result {Clone()}; 582 result.Insert<true>(other.repr_.cbegin(), other.repr_.cend()); 583 return result; 584 } 585 Union(const LargeRepr & other)586 IntSet<T, THRESHOLD> Union(const LargeRepr &other) const override 587 { 588 return {repr_ | other.repr_}; 589 } 590 UnionInPlace(const LargeRepr & other)591 void UnionInPlace(const LargeRepr &other) 592 { 593 ResizeUpOnly(other.repr_.size()); 594 repr_ |= other.repr_; 595 } 596 Clone()597 MPandaUniquePtr<Repr> Clone() const override 598 { 599 return MMakePandaUnique<LargeRepr>(repr_); 600 } 601 cbegin()602 const_iterator cbegin() const override 603 { 604 auto stream = repr_.LazyIndicesOf<1>(); 605 Index<T> start_idx = stream(); 606 return const_iterator::make(std::move(stream), start_idx); 607 } 608 cend()609 const_iterator cend() const override 610 { 611 return const_iterator::make(repr_.LazyIndicesOf<1>(), Index<T>()); 612 } 613 614 template <bool known_to_be_sorted, typename Iter> InsertManyImpl(Iter begin,Iter end)615 void InsertManyImpl(Iter begin, Iter end) 616 { 617 while (begin != end) { 618 Insert(*begin); 619 ++begin; 620 } 621 } 622 623 template <typename Handler> ForAll(Handler && handler)624 bool ForAll(Handler &&handler) const 625 { 626 return repr_.for_all_idx_of<1>(std::move(handler)); 627 } 628 AsStream()629 auto AsStream() const 630 { 631 return repr_.LazyIndicesOf<1>(); 632 } 633 634 private: 635 BitVector repr_; 636 ResizeDownOnly(size_t sz)637 void ResizeDownOnly(size_t sz) 638 { 639 if (sz < repr_.size()) { 640 repr_.resize(sz); 641 } 642 } 643 ResizeUpOnly(size_t sz)644 void ResizeUpOnly(size_t sz) 645 { 646 if (sz > repr_.size()) { 647 repr_.resize(sz); 648 } 649 } 650 651 friend class IntSet; 652 }; 653 654 class ConstIterRepr { 655 public: 656 // or return Repr? 657 virtual ReprType Type() const = 0; 658 virtual void Increment() = 0; 659 // for non-const iterator needs to return a proxy reference similar to vector<bool>::reference 660 virtual T Deref() const = 0; 661 // just for the same type 662 virtual bool Equals(const ConstIterRepr &other) const = 0; 663 // for postfix increment 664 virtual MPandaUniquePtr<ConstIterRepr> Clone() const = 0; 665 virtual ~ConstIterRepr() = default; 666 }; 667 668 class SmallConstIterRepr final : public ConstIterRepr { 669 public: SmallConstIterRepr(typename MPandaVector<T>::const_iterator repr)670 SmallConstIterRepr(typename MPandaVector<T>::const_iterator repr) : repr_ {repr} {}; 671 ~SmallConstIterRepr() = default; 672 Type()673 ReprType Type() const override 674 { 675 return ReprType::SMALL; 676 } 677 Increment()678 void Increment() override 679 { 680 ++repr_; 681 } 682 Deref()683 T Deref() const override 684 { 685 return *repr_; 686 } 687 Equals(const ConstIterRepr & other)688 bool Equals(const ConstIterRepr &other) const override 689 { 690 return static_cast<const SmallConstIterRepr &>(other).repr_ == repr_; 691 } 692 Clone()693 MPandaUniquePtr<ConstIterRepr> Clone() const override 694 { 695 return MMakePandaUnique<SmallConstIterRepr>(repr_); 696 } 697 698 private: 699 typename MPandaVector<T>::const_iterator repr_; 700 }; 701 702 template <typename Stream> 703 class LargeConstIterRepr final : public ConstIterRepr { 704 public: LargeConstIterRepr(Stream && stream,Index<T> index)705 LargeConstIterRepr(Stream &&stream, Index<T> index) : stream_ {std::move(stream)}, index_ {index} {}; 706 ~LargeConstIterRepr() = default; 707 Type()708 ReprType Type() const override 709 { 710 return ReprType::LARGE; 711 } 712 Increment()713 void Increment() override 714 { 715 if (index_.IsValid()) { 716 index_ = stream_(); 717 } 718 } 719 Deref()720 T Deref() const override 721 { 722 if (index_.IsValid()) { 723 return index_; 724 } else { 725 // or should this throw? 726 UNREACHABLE(); 727 } 728 } 729 Equals(const ConstIterRepr & other)730 bool Equals(const ConstIterRepr &other) const override 731 { 732 // not really safe, but we shouldn't be comparing iterators of different bitvectors anywhere 733 auto other1 = static_cast<const LargeConstIterRepr &>(other); 734 return other1.index_ == index_; 735 } 736 Clone()737 MPandaUniquePtr<ConstIterRepr> Clone() const override 738 { 739 return MMakePandaUnique<LargeConstIterRepr>(Stream {stream_}, index_); 740 } 741 742 private: 743 Stream stream_; 744 Index<T> index_; 745 }; 746 747 friend class const_iterator; 748 friend class SmallRepr; 749 friend class LargeRepr; 750 751 MPandaUniquePtr<Repr> repr_; 752 IntSet(MPandaVector<T> set)753 IntSet(MPandaVector<T> set) : repr_ {MMakePandaUnique<SmallRepr>(set)} {}; IntSet(BitVector set)754 IntSet(BitVector set) : repr_ {MMakePandaUnique<LargeRepr>(set)} {}; IntSet(MPandaUniquePtr<Repr> && repr)755 IntSet(MPandaUniquePtr<Repr> &&repr) : repr_ {std::move(repr)} {}; 756 757 // unsafe! AsSmallRepr()758 const SmallRepr &AsSmallRepr() const 759 { 760 return *static_cast<const SmallRepr *>(repr_.get()); 761 } 762 AsLargeRepr()763 const LargeRepr &AsLargeRepr() const 764 { 765 return *static_cast<const LargeRepr *>(repr_.get()); 766 } 767 AsSmallRepr()768 SmallRepr &AsSmallRepr() 769 { 770 return *static_cast<SmallRepr *>(repr_.get()); 771 } 772 AsLargeRepr()773 LargeRepr &AsLargeRepr() 774 { 775 return *static_cast<LargeRepr *>(repr_.get()); 776 } 777 778 template <typename SmallCase, typename LargeCase> SwitchOnRepr(SmallCase && smallCase,LargeCase && largeCase)779 auto SwitchOnRepr(SmallCase &&smallCase, LargeCase &&largeCase) const 780 { 781 switch (repr_->Type()) { 782 case ReprType::SMALL: 783 return smallCase(AsSmallRepr()); 784 case ReprType::LARGE: 785 return largeCase(AsLargeRepr()); 786 default: 787 UNREACHABLE(); 788 } 789 } 790 791 template <typename CommonCase> SwitchOnRepr(CommonCase && commonCase)792 auto SwitchOnRepr(CommonCase &&commonCase) const 793 { 794 return SwitchOnRepr(commonCase, commonCase); 795 } 796 MoveToLargeRepr()797 void MoveToLargeRepr() 798 { 799 repr_ = MMakePandaUnique<LargeRepr>(VectorToBitVector(AsSmallRepr().repr_)); 800 } 801 MoveToSmallRepr()802 void MoveToSmallRepr() 803 { 804 repr_ = MMakePandaUnique<SmallRepr>(BitVectorToVector(AsLargeRepr().repr_)); 805 } 806 BitVectorToVector(const BitVector & bv)807 static MPandaVector<T> BitVectorToVector(const BitVector &bv) 808 { 809 MPandaVector<T> res; 810 bv.for_all_idx_of<1>([&](size_t idx) { 811 res.push_back(idx); 812 return true; 813 }); 814 return res; 815 } 816 VectorToBitVector(const MPandaVector<T> & vec)817 static BitVector VectorToBitVector(const MPandaVector<T> &vec) 818 { 819 BitVector bv(*vec.rbegin() * 3U / 2U); 820 for (T y : vec) { 821 bv.Set(y); 822 } 823 return bv; 824 } 825 }; 826 827 template <typename T, size_t THRESHOLD> 828 std::ostream &operator<<(std::ostream &os, const IntSet<T, THRESHOLD> &set) 829 { 830 os << "IntSet{"; 831 bool first = true; 832 set.ForAll([&](T value) { 833 if (first) { 834 first = false; 835 } else { 836 os << " "; 837 } 838 os << value; 839 return true; 840 }); 841 os << "}"; 842 return os; 843 } 844 845 } // namespace panda::verifier 846 847 #endif // PANDA_VERIFICATION_UTIL_INT_SET_H_ 848