1// Copyright 2015, VIXL authors 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are met: 6// 7// * Redistributions of source code must retain the above copyright notice, 8// this list of conditions and the following disclaimer. 9// * Redistributions in binary form must reproduce the above copyright notice, 10// this list of conditions and the following disclaimer in the documentation 11// and/or other materials provided with the distribution. 12// * Neither the name of ARM Limited nor the names of its contributors may be 13// used to endorse or promote products derived from this software without 14// specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27#ifndef VIXL_INVALSET_H_ 28#define VIXL_INVALSET_H_ 29 30#include <algorithm> 31#include <cstring> 32#include <vector> 33 34#include "globals-vixl.h" 35#include "utils-vixl.h" 36 37namespace vixl { 38 39// We define a custom data structure template and its iterator as `std` 40// containers do not fit the performance requirements for some of our use cases. 41// 42// The structure behaves like an iterable unordered set with special properties 43// and restrictions. "InvalSet" stands for "Invalidatable Set". 44// 45// Restrictions and requirements: 46// - Adding an element already present in the set is illegal. In debug mode, 47// this is checked at insertion time. 48// - The templated class `ElementType` must provide comparison operators so that 49// `std::sort()` can be used. 50// - A key must be available to represent invalid elements. 51// - Elements with an invalid key must compare higher or equal to any other 52// element. 53// 54// Use cases and performance considerations: 55// Our use cases present two specificities that allow us to design this 56// structure to provide fast insertion *and* fast search and deletion 57// operations: 58// - Elements are (generally) inserted in order (sorted according to their key). 59// - A key is available to mark elements as invalid (deleted). 60// The backing `std::vector` allows for fast insertions. When 61// searching for an element we ensure the elements are sorted (this is generally 62// the case) and perform a binary search. When deleting an element we do not 63// free the associated memory immediately. Instead, an element to be deleted is 64// marked with the 'invalid' key. Other methods of the container take care of 65// ignoring entries marked as invalid. 66// To avoid the overhead of the `std::vector` container when only few entries 67// are used, a number of elements are preallocated. 68 69// 'ElementType' and 'KeyType' are respectively the types of the elements and 70// their key. The structure only reclaims memory when safe to do so, if the 71// number of elements that can be reclaimed is greater than `RECLAIM_FROM` and 72// greater than `<total number of elements> / RECLAIM_FACTOR. 73// clang-format off 74#define TEMPLATE_INVALSET_P_DECL \ 75 class ElementType, \ 76 unsigned N_PREALLOCATED_ELEMENTS, \ 77 class KeyType, \ 78 KeyType INVALID_KEY, \ 79 size_t RECLAIM_FROM, \ 80 unsigned RECLAIM_FACTOR 81// clang-format on 82 83#define TEMPLATE_INVALSET_P_DEF \ 84 ElementType, N_PREALLOCATED_ELEMENTS, KeyType, INVALID_KEY, RECLAIM_FROM, \ 85 RECLAIM_FACTOR 86 87template <class S> 88class InvalSetIterator; // Forward declaration. 89 90template <TEMPLATE_INVALSET_P_DECL> 91class InvalSet { 92 public: 93#ifndef PANDA_BUILD 94 InvalSet(); 95#else 96 InvalSet() = delete; 97 InvalSet(AllocatorWrapper alocator); 98 InvalSet(InvalSet&&) = default; 99#endif 100 ~InvalSet() VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION; 101 102 static const size_t kNPreallocatedElements = N_PREALLOCATED_ELEMENTS; 103 static const KeyType kInvalidKey = INVALID_KEY; 104 105 // C++ STL iterator interface. 106 typedef InvalSetIterator<InvalSet<TEMPLATE_INVALSET_P_DEF> > iterator; 107 iterator begin(); 108 iterator end(); 109 110 // It is illegal to insert an element already present in the set. 111 void insert(const ElementType& element); 112 113 // Looks for the specified element in the set and - if found - deletes it. 114 // The return value is the number of elements erased: either 0 or 1. 115 size_t erase(const ElementType& element); 116 117 // This indicates the number of (valid) elements stored in this set. 118 size_t size() const; 119 120 // Returns true if no elements are stored in the set. 121 // Note that this does not mean the backing storage is empty: it can still 122 // contain invalid elements. 123 bool empty() const; 124 125 void clear(); 126 127 const ElementType GetMinElement(); 128 129 // This returns the key of the minimum element in the set. 130 KeyType GetMinElementKey(); 131 132 static bool IsValid(const ElementType& element); 133 static KeyType GetKey(const ElementType& element); 134 static void SetKey(ElementType* element, KeyType key); 135 136 typedef ElementType _ElementType; 137 typedef KeyType _KeyType; 138 139 protected: 140 // Returns a pointer to the element in vector_ if it was found, or NULL 141 // otherwise. 142 ElementType* Search(const ElementType& element); 143 144 // The argument *must* point to an element stored in *this* set. 145 // This function is not allowed to move elements in the backing vector 146 // storage. 147 void EraseInternal(ElementType* element); 148 149 // The elements in the range searched must be sorted. 150 ElementType* BinarySearch(const ElementType& element, 151 ElementType* start, 152 ElementType* end) const; 153 154 // Sort the elements. 155 enum SortType { 156 // The 'hard' version guarantees that invalid elements are moved to the end 157 // of the container. 158 kHardSort, 159 // The 'soft' version only guarantees that the elements will be sorted. 160 // Invalid elements may still be present anywhere in the set. 161 kSoftSort 162 }; 163 void Sort(SortType sort_type); 164 165 // Delete the elements that have an invalid key. The complexity is linear 166 // with the size of the vector. 167 void Clean(); 168 169 const ElementType Front() const; 170 const ElementType Back() const; 171 172 // Delete invalid trailing elements and return the last valid element in the 173 // set. 174 const ElementType CleanBack(); 175 176 // Returns a pointer to the start or end of the backing storage. 177 const ElementType* StorageBegin() const; 178 const ElementType* StorageEnd() const; 179 ElementType* StorageBegin(); 180 ElementType* StorageEnd(); 181 182 // Returns the index of the element within the backing storage. The element 183 // must belong to the backing storage. 184 size_t GetElementIndex(const ElementType* element) const; 185 186 // Returns the element at the specified index in the backing storage. 187 const ElementType* GetElementAt(size_t index) const; 188 ElementType* GetElementAt(size_t index); 189 190 static const ElementType* GetFirstValidElement(const ElementType* from, 191 const ElementType* end); 192 193 void CacheMinElement(); 194 const ElementType GetCachedMinElement() const; 195 196 bool ShouldReclaimMemory() const; 197 void ReclaimMemory(); 198 199 bool IsUsingVector() const { return vector_ != NULL; } 200 void SetSorted(bool sorted) { sorted_ = sorted; } 201 202 // We cache some data commonly required by users to improve performance. 203 // We cannot cache pointers to elements as we do not control the backing 204 // storage. 205 bool valid_cached_min_; 206 size_t cached_min_index_; // Valid iff `valid_cached_min_` is true. 207 KeyType cached_min_key_; // Valid iff `valid_cached_min_` is true. 208 209 // Indicates whether the elements are sorted. 210 bool sorted_; 211 212 // This represents the number of (valid) elements in this set. 213 size_t size_; 214 215 // The backing storage is either the array of preallocated elements or the 216 // vector. The structure starts by using the preallocated elements, and 217 // transitions (permanently) to using the vector once more than 218 // kNPreallocatedElements are used. 219 // Elements are only invalidated when using the vector. The preallocated 220 // storage always only contains valid elements. 221 ElementType preallocated_[kNPreallocatedElements]; 222#ifdef PANDA_BUILD 223 AllocatorWrapper allocator_; 224 Vector<ElementType>* vector_; 225#else 226 std::vector<ElementType>* vector_; 227#endif 228 229 // Iterators acquire and release this monitor. While a set is acquired, 230 // certain operations are illegal to ensure that the iterator will 231 // correctly iterate over the elements in the set. 232 int monitor_; 233#ifdef VIXL_DEBUG 234 int monitor() const { return monitor_; } 235 void Acquire() { monitor_++; } 236 void Release() { 237 monitor_--; 238 VIXL_ASSERT(monitor_ >= 0); 239 } 240#endif 241 242 private: 243// The copy constructor and assignment operator are not used and the defaults 244// are unsafe, so disable them (without an implementation). 245#if __cplusplus >= 201103L 246 InvalSet(const InvalSet& other) = delete; 247 InvalSet operator=(const InvalSet& other) = delete; 248#else 249 InvalSet(const InvalSet& other); 250 InvalSet operator=(const InvalSet& other); 251#endif 252 253 friend class InvalSetIterator<InvalSet<TEMPLATE_INVALSET_P_DEF> >; 254}; 255 256 257template <class S> 258class InvalSetIterator { 259 using iterator_category = std::forward_iterator_tag; 260 using value_type = typename S::_ElementType; 261 using difference_type = std::ptrdiff_t; 262 using pointer = S*; 263 using reference = S&; 264 265 private: 266 // Redefine types to mirror the associated set types. 267 typedef typename S::_ElementType ElementType; 268 typedef typename S::_KeyType KeyType; 269 270 public: 271 explicit InvalSetIterator(S* inval_set = NULL); 272 273 // This class implements the standard copy-swap idiom. 274 ~InvalSetIterator(); 275 InvalSetIterator(const InvalSetIterator<S>& other); 276 InvalSetIterator<S>& operator=(InvalSetIterator<S> other); 277#if __cplusplus >= 201103L 278 InvalSetIterator(InvalSetIterator<S>&& other) noexcept; 279#endif 280 281 friend void swap(InvalSetIterator<S>& a, InvalSetIterator<S>& b) { 282 using std::swap; 283 swap(a.using_vector_, b.using_vector_); 284 swap(a.index_, b.index_); 285 swap(a.inval_set_, b.inval_set_); 286 swap(a.iterator_, b.iterator_); 287 } 288 289 // Return true if the iterator is at the end of the set. 290 bool Done() const; 291 292 // Move this iterator to the end of the set. 293 void Finish(); 294 295 // Delete the current element and advance the iterator to point to the next 296 // element. 297 void DeleteCurrentAndAdvance(); 298 299 static bool IsValid(const ElementType& element); 300 static KeyType GetKey(const ElementType& element); 301 302 // Extra helpers to support the forward-iterator interface. 303 InvalSetIterator<S>& operator++(); // Pre-increment. 304 InvalSetIterator<S> operator++(int); // Post-increment. 305 bool operator==(const InvalSetIterator<S>& rhs) const; 306 bool operator!=(const InvalSetIterator<S>& rhs) const { 307 return !(*this == rhs); 308 } 309 ElementType& operator*() { return *Current(); } 310 const ElementType& operator*() const { return *Current(); } 311 ElementType* operator->() { return Current(); } 312 const ElementType* operator->() const { return Current(); } 313 314 protected: 315 void MoveToValidElement(); 316 317 // Indicates if the iterator is looking at the vector or at the preallocated 318 // elements. 319 bool using_vector_; 320 // Used when looking at the preallocated elements, or in debug mode when using 321 // the vector to track how many times the iterator has advanced. 322 size_t index_; 323 typename Vector<ElementType>::iterator iterator_; 324 S* inval_set_; 325 326 // TODO: These helpers are deprecated and will be removed in future versions 327 // of VIXL. 328 ElementType* Current() const; 329 void Advance(); 330}; 331 332#ifndef PANDA_BUILD 333template <TEMPLATE_INVALSET_P_DECL> 334InvalSet<TEMPLATE_INVALSET_P_DEF>::InvalSet() 335 : valid_cached_min_(false), sorted_(true), size_(0), vector_(NULL) { 336#ifdef VIXL_DEBUG 337 monitor_ = 0; 338#endif 339} 340#else 341template <TEMPLATE_INVALSET_P_DECL> 342InvalSet<TEMPLATE_INVALSET_P_DEF>::InvalSet(AllocatorWrapper allocator) 343 : valid_cached_min_(false), sorted_(true), size_(0), allocator_(allocator), vector_(NULL) { 344#ifdef VIXL_DEBUG 345 monitor_ = 0; 346#endif 347} 348#endif 349 350template <TEMPLATE_INVALSET_P_DECL> 351InvalSet<TEMPLATE_INVALSET_P_DEF>::~InvalSet() 352 VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION { 353 VIXL_ASSERT(monitor_ == 0); 354#ifndef VIXL_USE_PANDA_ALLOC 355 delete vector_; 356#endif 357} 358 359 360template <TEMPLATE_INVALSET_P_DECL> 361typename InvalSet<TEMPLATE_INVALSET_P_DEF>::iterator 362InvalSet<TEMPLATE_INVALSET_P_DEF>::begin() { 363 return iterator(this); 364} 365 366 367template <TEMPLATE_INVALSET_P_DECL> 368typename InvalSet<TEMPLATE_INVALSET_P_DEF>::iterator 369InvalSet<TEMPLATE_INVALSET_P_DEF>::end() { 370 iterator end(this); 371 end.Finish(); 372 return end; 373} 374 375 376template <TEMPLATE_INVALSET_P_DECL> 377void InvalSet<TEMPLATE_INVALSET_P_DEF>::insert(const ElementType& element) { 378 VIXL_ASSERT(monitor() == 0); 379 VIXL_ASSERT(IsValid(element)); 380 VIXL_ASSERT(Search(element) == NULL); 381 SetSorted(empty() || (sorted_ && (element > CleanBack()))); 382 if (IsUsingVector()) { 383 vector_->push_back(element); 384 } else { 385 if (size_ < kNPreallocatedElements) { 386 preallocated_[size_] = element; 387 } else { 388 // Transition to using the vector. 389#ifndef PANDA_BUILD 390 vector_ = 391 new std::vector<ElementType>(preallocated_, preallocated_ + size_); 392#else 393 vector_ = allocator_.New<Vector<ElementType>>( 394 preallocated_, preallocated_ + size_, allocator_.Adapter()); 395#endif 396 vector_->push_back(element); 397 } 398 } 399 size_++; 400 401 if (valid_cached_min_ && (element < GetMinElement())) { 402 cached_min_index_ = IsUsingVector() ? vector_->size() - 1 : size_ - 1; 403 cached_min_key_ = GetKey(element); 404 valid_cached_min_ = true; 405 } 406 407 if (ShouldReclaimMemory()) { 408 ReclaimMemory(); 409 } 410} 411 412 413template <TEMPLATE_INVALSET_P_DECL> 414size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::erase(const ElementType& element) { 415 VIXL_ASSERT(monitor() == 0); 416 VIXL_ASSERT(IsValid(element)); 417 ElementType* local_element = Search(element); 418 if (local_element != NULL) { 419 EraseInternal(local_element); 420 return 1; 421 } 422 return 0; 423} 424 425 426template <TEMPLATE_INVALSET_P_DECL> 427ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::Search( 428 const ElementType& element) { 429 VIXL_ASSERT(monitor() == 0); 430 if (empty()) { 431 return NULL; 432 } 433 if (ShouldReclaimMemory()) { 434 ReclaimMemory(); 435 } 436 if (!sorted_) { 437 Sort(kHardSort); 438 } 439 if (!valid_cached_min_) { 440 CacheMinElement(); 441 } 442 return BinarySearch(element, GetElementAt(cached_min_index_), StorageEnd()); 443} 444 445 446template <TEMPLATE_INVALSET_P_DECL> 447size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::size() const { 448 return size_; 449} 450 451 452template <TEMPLATE_INVALSET_P_DECL> 453bool InvalSet<TEMPLATE_INVALSET_P_DEF>::empty() const { 454 return size_ == 0; 455} 456 457 458template <TEMPLATE_INVALSET_P_DECL> 459void InvalSet<TEMPLATE_INVALSET_P_DEF>::clear() { 460 VIXL_ASSERT(monitor() == 0); 461 size_ = 0; 462 if (IsUsingVector()) { 463 vector_->clear(); 464 } 465 SetSorted(true); 466 valid_cached_min_ = false; 467} 468 469 470template <TEMPLATE_INVALSET_P_DECL> 471const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::GetMinElement() { 472 VIXL_ASSERT(monitor() == 0); 473 VIXL_ASSERT(!empty()); 474 CacheMinElement(); 475 return *GetElementAt(cached_min_index_); 476} 477 478 479template <TEMPLATE_INVALSET_P_DECL> 480KeyType InvalSet<TEMPLATE_INVALSET_P_DEF>::GetMinElementKey() { 481 VIXL_ASSERT(monitor() == 0); 482 if (valid_cached_min_) { 483 return cached_min_key_; 484 } else { 485 return GetKey(GetMinElement()); 486 } 487} 488 489 490template <TEMPLATE_INVALSET_P_DECL> 491bool InvalSet<TEMPLATE_INVALSET_P_DEF>::IsValid(const ElementType& element) { 492 return GetKey(element) != kInvalidKey; 493} 494 495 496template <TEMPLATE_INVALSET_P_DECL> 497void InvalSet<TEMPLATE_INVALSET_P_DEF>::EraseInternal(ElementType* element) { 498 // Note that this function must be safe even while an iterator has acquired 499 // this set. 500 VIXL_ASSERT(element != NULL); 501 size_t deleted_index = GetElementIndex(element); 502 if (IsUsingVector()) { 503 VIXL_ASSERT((&(vector_->front()) <= element) && 504 (element <= &(vector_->back()))); 505 SetKey(element, kInvalidKey); 506 } else { 507 VIXL_ASSERT((preallocated_ <= element) && 508 (element < (preallocated_ + kNPreallocatedElements))); 509 ElementType* end = preallocated_ + kNPreallocatedElements; 510 size_t copy_size = sizeof(*element) * (end - element - 1); 511 memmove(element, element + 1, copy_size); 512 } 513 size_--; 514 515 if (valid_cached_min_ && (deleted_index == cached_min_index_)) { 516 if (sorted_ && !empty()) { 517 const ElementType* min = GetFirstValidElement(element, StorageEnd()); 518 cached_min_index_ = GetElementIndex(min); 519 cached_min_key_ = GetKey(*min); 520 valid_cached_min_ = true; 521 } else { 522 valid_cached_min_ = false; 523 } 524 } 525} 526 527 528template <TEMPLATE_INVALSET_P_DECL> 529ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::BinarySearch( 530 const ElementType& element, ElementType* start, ElementType* end) const { 531 if (start == end) { 532 return NULL; 533 } 534 VIXL_ASSERT(sorted_); 535 VIXL_ASSERT(start < end); 536 VIXL_ASSERT(!empty()); 537 538 // Perform a binary search through the elements while ignoring invalid 539 // elements. 540 ElementType* elements = start; 541 size_t low = 0; 542 size_t high = (end - start) - 1; 543 while (low < high) { 544 // Find valid bounds. 545 while (!IsValid(elements[low]) && (low < high)) ++low; 546 while (!IsValid(elements[high]) && (low < high)) --high; 547 VIXL_ASSERT(low <= high); 548 // Avoid overflow when computing the middle index. 549 size_t middle = low + (high - low) / 2; 550 if ((middle == low) || (middle == high)) { 551 break; 552 } 553 while ((middle < high - 1) && !IsValid(elements[middle])) ++middle; 554 while ((low + 1 < middle) && !IsValid(elements[middle])) --middle; 555 if (!IsValid(elements[middle])) { 556 break; 557 } 558 if (elements[middle] < element) { 559 low = middle; 560 } else { 561 high = middle; 562 } 563 } 564 565 if (elements[low] == element) return &elements[low]; 566 if (elements[high] == element) return &elements[high]; 567 return NULL; 568} 569 570 571template <TEMPLATE_INVALSET_P_DECL> 572void InvalSet<TEMPLATE_INVALSET_P_DEF>::Sort(SortType sort_type) { 573 if (sort_type == kSoftSort) { 574 if (sorted_) { 575 return; 576 } 577 } 578 VIXL_ASSERT(monitor() == 0); 579 if (empty()) { 580 return; 581 } 582 583 Clean(); 584 std::sort(StorageBegin(), StorageEnd()); 585 586 SetSorted(true); 587 cached_min_index_ = 0; 588 cached_min_key_ = GetKey(Front()); 589 valid_cached_min_ = true; 590} 591 592 593template <TEMPLATE_INVALSET_P_DECL> 594void InvalSet<TEMPLATE_INVALSET_P_DEF>::Clean() { 595 VIXL_ASSERT(monitor() == 0); 596 if (empty() || !IsUsingVector()) { 597 return; 598 } 599 // Manually iterate through the vector storage to discard invalid elements. 600 ElementType* start = &(vector_->front()); 601 ElementType* end = start + vector_->size(); 602 ElementType* c = start; 603 ElementType* first_invalid; 604 ElementType* first_valid; 605 ElementType* next_invalid; 606 607 while ((c < end) && IsValid(*c)) c++; 608 first_invalid = c; 609 610 while (c < end) { 611 while ((c < end) && !IsValid(*c)) c++; 612 first_valid = c; 613 while ((c < end) && IsValid(*c)) c++; 614 next_invalid = c; 615 616 ptrdiff_t n_moved_elements = (next_invalid - first_valid); 617 memmove(first_invalid, first_valid, n_moved_elements * sizeof(*c)); 618 first_invalid = first_invalid + n_moved_elements; 619 c = next_invalid; 620 } 621 622 // Delete the trailing invalid elements. 623 vector_->erase(vector_->begin() + (first_invalid - start), vector_->end()); 624 VIXL_ASSERT(vector_->size() == size_); 625 626 if (sorted_) { 627 valid_cached_min_ = true; 628 cached_min_index_ = 0; 629 cached_min_key_ = GetKey(*GetElementAt(0)); 630 } else { 631 valid_cached_min_ = false; 632 } 633} 634 635 636template <TEMPLATE_INVALSET_P_DECL> 637const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Front() const { 638 VIXL_ASSERT(!empty()); 639 return IsUsingVector() ? vector_->front() : preallocated_[0]; 640} 641 642 643template <TEMPLATE_INVALSET_P_DECL> 644const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Back() const { 645 VIXL_ASSERT(!empty()); 646 return IsUsingVector() ? vector_->back() : preallocated_[size_ - 1]; 647} 648 649 650template <TEMPLATE_INVALSET_P_DECL> 651const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::CleanBack() { 652 VIXL_ASSERT(monitor() == 0); 653 if (IsUsingVector()) { 654 // Delete the invalid trailing elements. 655 typename Vector<ElementType>::reverse_iterator it = vector_->rbegin(); 656 while (!IsValid(*it)) { 657 it++; 658 } 659 vector_->erase(it.base(), vector_->end()); 660 } 661 return Back(); 662} 663 664 665template <TEMPLATE_INVALSET_P_DECL> 666const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() const { 667 return IsUsingVector() ? &(vector_->front()) : preallocated_; 668} 669 670 671template <TEMPLATE_INVALSET_P_DECL> 672const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() const { 673 return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_; 674} 675 676 677template <TEMPLATE_INVALSET_P_DECL> 678ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() { 679 return IsUsingVector() ? &(vector_->front()) : preallocated_; 680} 681 682 683template <TEMPLATE_INVALSET_P_DECL> 684ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() { 685 return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_; 686} 687 688 689template <TEMPLATE_INVALSET_P_DECL> 690size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::GetElementIndex( 691 const ElementType* element) const { 692 VIXL_ASSERT((StorageBegin() <= element) && (element < StorageEnd())); 693 return element - StorageBegin(); 694} 695 696 697template <TEMPLATE_INVALSET_P_DECL> 698const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::GetElementAt( 699 size_t index) const { 700 VIXL_ASSERT((IsUsingVector() && (index < vector_->size())) || 701 (index < size_)); 702 return StorageBegin() + index; 703} 704 705template <TEMPLATE_INVALSET_P_DECL> 706ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::GetElementAt(size_t index) { 707 VIXL_ASSERT((IsUsingVector() && (index < vector_->size())) || 708 (index < size_)); 709 return StorageBegin() + index; 710} 711 712template <TEMPLATE_INVALSET_P_DECL> 713const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::GetFirstValidElement( 714 const ElementType* from, const ElementType* end) { 715 while ((from < end) && !IsValid(*from)) { 716 from++; 717 } 718 return from; 719} 720 721 722template <TEMPLATE_INVALSET_P_DECL> 723void InvalSet<TEMPLATE_INVALSET_P_DEF>::CacheMinElement() { 724 VIXL_ASSERT(monitor() == 0); 725 VIXL_ASSERT(!empty()); 726 727 if (valid_cached_min_) { 728 return; 729 } 730 731 if (sorted_) { 732 const ElementType* min = GetFirstValidElement(StorageBegin(), StorageEnd()); 733 cached_min_index_ = GetElementIndex(min); 734 cached_min_key_ = GetKey(*min); 735 valid_cached_min_ = true; 736 } else { 737 Sort(kHardSort); 738 } 739 VIXL_ASSERT(valid_cached_min_); 740} 741 742 743template <TEMPLATE_INVALSET_P_DECL> 744bool InvalSet<TEMPLATE_INVALSET_P_DEF>::ShouldReclaimMemory() const { 745 if (!IsUsingVector()) { 746 return false; 747 } 748 size_t n_invalid_elements = vector_->size() - size_; 749 return (n_invalid_elements > RECLAIM_FROM) && 750 (n_invalid_elements > vector_->size() / RECLAIM_FACTOR); 751} 752 753 754template <TEMPLATE_INVALSET_P_DECL> 755void InvalSet<TEMPLATE_INVALSET_P_DEF>::ReclaimMemory() { 756 VIXL_ASSERT(monitor() == 0); 757 Clean(); 758} 759 760 761template <class S> 762InvalSetIterator<S>::InvalSetIterator(S* inval_set) 763 : using_vector_((inval_set != NULL) && inval_set->IsUsingVector()), 764 index_(0), 765 inval_set_(inval_set) { 766 if (inval_set != NULL) { 767 inval_set->Sort(S::kSoftSort); 768#ifdef VIXL_DEBUG 769 inval_set->Acquire(); 770#endif 771 if (using_vector_) { 772#ifndef PANDA_BUILD 773 iterator_ = typename std::vector<ElementType>::iterator( 774 inval_set_->vector_->begin()); 775#else 776 iterator_ = typename Vector<ElementType>::iterator( 777 inval_set_->vector_->begin()); 778#endif 779 } 780 MoveToValidElement(); 781 } 782} 783 784 785template <class S> 786InvalSetIterator<S>::~InvalSetIterator() { 787#ifdef VIXL_DEBUG 788 if (inval_set_ != NULL) inval_set_->Release(); 789#endif 790} 791 792 793template <class S> 794typename S::_ElementType* InvalSetIterator<S>::Current() const { 795 VIXL_ASSERT(!Done()); 796 if (using_vector_) { 797 return &(*iterator_); 798 } else { 799 return &(inval_set_->preallocated_[index_]); 800 } 801} 802 803 804template <class S> 805void InvalSetIterator<S>::Advance() { 806 ++(*this); 807} 808 809 810template <class S> 811bool InvalSetIterator<S>::Done() const { 812 if (using_vector_) { 813 bool done = (iterator_ == inval_set_->vector_->end()); 814 VIXL_ASSERT(done == (index_ == inval_set_->size())); 815 return done; 816 } else { 817 return index_ == inval_set_->size(); 818 } 819} 820 821 822template <class S> 823void InvalSetIterator<S>::Finish() { 824 VIXL_ASSERT(inval_set_->sorted_); 825 if (using_vector_) { 826 iterator_ = inval_set_->vector_->end(); 827 } 828 index_ = inval_set_->size(); 829} 830 831 832template <class S> 833void InvalSetIterator<S>::DeleteCurrentAndAdvance() { 834 if (using_vector_) { 835 inval_set_->EraseInternal(&(*iterator_)); 836 MoveToValidElement(); 837 } else { 838 inval_set_->EraseInternal(inval_set_->preallocated_ + index_); 839 } 840} 841 842 843template <class S> 844bool InvalSetIterator<S>::IsValid(const ElementType& element) { 845 return S::IsValid(element); 846} 847 848 849template <class S> 850typename S::_KeyType InvalSetIterator<S>::GetKey(const ElementType& element) { 851 return S::GetKey(element); 852} 853 854 855template <class S> 856void InvalSetIterator<S>::MoveToValidElement() { 857 if (using_vector_) { 858 while ((iterator_ != inval_set_->vector_->end()) && !IsValid(*iterator_)) { 859 iterator_++; 860 } 861 } else { 862 VIXL_ASSERT(inval_set_->empty() || IsValid(inval_set_->preallocated_[0])); 863 // Nothing to do. 864 } 865} 866 867 868template <class S> 869InvalSetIterator<S>::InvalSetIterator(const InvalSetIterator<S>& other) 870 : using_vector_(other.using_vector_), 871 index_(other.index_), 872 inval_set_(other.inval_set_), 873 iterator_(other.iterator_) { 874#ifdef VIXL_DEBUG 875 if (inval_set_ != NULL) inval_set_->Acquire(); 876#endif 877} 878 879 880#if __cplusplus >= 201103L 881template <class S> 882InvalSetIterator<S>::InvalSetIterator(InvalSetIterator<S>&& other) noexcept 883 : using_vector_(false), index_(0), inval_set_(NULL) { 884 swap(*this, other); 885} 886#endif 887 888 889template <class S> 890InvalSetIterator<S>& InvalSetIterator<S>::operator=(InvalSetIterator<S> other) { 891 swap(*this, other); 892 return *this; 893} 894 895 896template <class S> 897bool InvalSetIterator<S>::operator==(const InvalSetIterator<S>& rhs) const { 898 bool equal = (inval_set_ == rhs.inval_set_); 899 900 // If the inval_set_ matches, using_vector_ must also match. 901 VIXL_ASSERT(!equal || (using_vector_ == rhs.using_vector_)); 902 903 if (using_vector_) { 904 equal = equal && (iterator_ == rhs.iterator_); 905 // In debug mode, index_ is maintained even with using_vector_. 906 VIXL_ASSERT(!equal || (index_ == rhs.index_)); 907 } else { 908 equal = equal && (index_ == rhs.index_); 909#ifdef DEBUG 910 // If not using_vector_, iterator_ should be default-initialised. 911#ifndef PANDA_BUILD 912 typename std::vector<ElementType>::iterator default_iterator; 913#else 914 typename Vector<ElementType>::iterator default_iterator; 915#endif 916 VIXL_ASSERT(iterator_ == default_iterator); 917 VIXL_ASSERT(rhs.iterator_ == default_iterator); 918#endif 919 } 920 return equal; 921} 922 923 924template <class S> 925InvalSetIterator<S>& InvalSetIterator<S>::operator++() { 926 // Pre-increment. 927 VIXL_ASSERT(!Done()); 928 if (using_vector_) { 929 iterator_++; 930#ifdef VIXL_DEBUG 931 index_++; 932#endif 933 MoveToValidElement(); 934 } else { 935 index_++; 936 } 937 return *this; 938} 939 940 941template <class S> 942InvalSetIterator<S> InvalSetIterator<S>::operator++(int /* unused */) { 943 // Post-increment. 944 VIXL_ASSERT(!Done()); 945 InvalSetIterator<S> old(*this); 946 ++(*this); 947 return old; 948} 949 950 951#undef TEMPLATE_INVALSET_P_DECL 952#undef TEMPLATE_INVALSET_P_DEF 953 954} // namespace vixl 955 956#endif // VIXL_INVALSET_H_ 957