invalset.h (23114B)
1// Copyright 2015, ARM Limited 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 <cstring> 31 32#include <algorithm> 33#include <vector> 34 35#include "vixl/globals.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#define TEMPLATE_INVALSET_P_DECL \ 74 class ElementType, \ 75 unsigned N_PREALLOCATED_ELEMENTS, \ 76 class KeyType, \ 77 KeyType INVALID_KEY, \ 78 size_t RECLAIM_FROM, \ 79 unsigned RECLAIM_FACTOR 80 81#define TEMPLATE_INVALSET_P_DEF \ 82ElementType, N_PREALLOCATED_ELEMENTS, \ 83KeyType, INVALID_KEY, RECLAIM_FROM, RECLAIM_FACTOR 84 85template<class S> class InvalSetIterator; // Forward declaration. 86 87template<TEMPLATE_INVALSET_P_DECL> class InvalSet { 88 public: 89 InvalSet(); 90 ~InvalSet(); 91 92 static const size_t kNPreallocatedElements = N_PREALLOCATED_ELEMENTS; 93 static const KeyType kInvalidKey = INVALID_KEY; 94 95 // It is illegal to insert an element already present in the set. 96 void insert(const ElementType& element); 97 98 // Looks for the specified element in the set and - if found - deletes it. 99 void erase(const ElementType& element); 100 101 // This indicates the number of (valid) elements stored in this set. 102 size_t size() const; 103 104 // Returns true if no elements are stored in the set. 105 // Note that this does not mean the the backing storage is empty: it can still 106 // contain invalid elements. 107 bool empty() const; 108 109 void clear(); 110 111 const ElementType min_element(); 112 113 // This returns the key of the minimum element in the set. 114 KeyType min_element_key(); 115 116 static bool IsValid(const ElementType& element); 117 static KeyType Key(const ElementType& element); 118 static void SetKey(ElementType* element, KeyType key); 119 120 protected: 121 // Returns a pointer to the element in vector_ if it was found, or NULL 122 // otherwise. 123 ElementType* Search(const ElementType& element); 124 125 // The argument *must* point to an element stored in *this* set. 126 // This function is not allowed to move elements in the backing vector 127 // storage. 128 void EraseInternal(ElementType* element); 129 130 // The elements in the range searched must be sorted. 131 ElementType* BinarySearch(const ElementType& element, 132 ElementType* start, 133 ElementType* end) const; 134 135 // Sort the elements. 136 enum SortType { 137 // The 'hard' version guarantees that invalid elements are moved to the end 138 // of the container. 139 kHardSort, 140 // The 'soft' version only guarantees that the elements will be sorted. 141 // Invalid elements may still be present anywhere in the set. 142 kSoftSort 143 }; 144 void Sort(SortType sort_type); 145 146 // Delete the elements that have an invalid key. The complexity is linear 147 // with the size of the vector. 148 void Clean(); 149 150 const ElementType Front() const; 151 const ElementType Back() const; 152 153 // Delete invalid trailing elements and return the last valid element in the 154 // set. 155 const ElementType CleanBack(); 156 157 // Returns a pointer to the start or end of the backing storage. 158 const ElementType* StorageBegin() const; 159 const ElementType* StorageEnd() const; 160 ElementType* StorageBegin(); 161 ElementType* StorageEnd(); 162 163 // Returns the index of the element within the backing storage. The element 164 // must belong to the backing storage. 165 size_t ElementIndex(const ElementType* element) const; 166 167 // Returns the element at the specified index in the backing storage. 168 const ElementType* ElementAt(size_t index) const; 169 ElementType* ElementAt(size_t index); 170 171 static const ElementType* FirstValidElement(const ElementType* from, 172 const ElementType* end); 173 174 void CacheMinElement(); 175 const ElementType CachedMinElement() const; 176 177 bool ShouldReclaimMemory() const; 178 void ReclaimMemory(); 179 180 bool IsUsingVector() const { return vector_ != NULL; } 181 void set_sorted(bool sorted) { sorted_ = sorted; } 182 183 // We cache some data commonly required by users to improve performance. 184 // We cannot cache pointers to elements as we do not control the backing 185 // storage. 186 bool valid_cached_min_; 187 size_t cached_min_index_; // Valid iff `valid_cached_min_` is true. 188 KeyType cached_min_key_; // Valid iff `valid_cached_min_` is true. 189 190 // Indicates whether the elements are sorted. 191 bool sorted_; 192 193 // This represents the number of (valid) elements in this set. 194 size_t size_; 195 196 // The backing storage is either the array of preallocated elements or the 197 // vector. The structure starts by using the preallocated elements, and 198 // transitions (permanently) to using the vector once more than 199 // kNPreallocatedElements are used. 200 // Elements are only invalidated when using the vector. The preallocated 201 // storage always only contains valid elements. 202 ElementType preallocated_[kNPreallocatedElements]; 203 std::vector<ElementType>* vector_; 204 205#ifdef VIXL_DEBUG 206 // Iterators acquire and release this monitor. While a set is acquired, 207 // certain operations are illegal to ensure that the iterator will 208 // correctly iterate over the elements in the set. 209 int monitor_; 210 int monitor() const { return monitor_; } 211 void Acquire() { monitor_++; } 212 void Release() { 213 monitor_--; 214 VIXL_ASSERT(monitor_ >= 0); 215 } 216#endif 217 218 friend class InvalSetIterator<InvalSet<TEMPLATE_INVALSET_P_DEF> >; 219 typedef ElementType _ElementType; 220 typedef KeyType _KeyType; 221}; 222 223 224template<class S> class InvalSetIterator { 225 private: 226 // Redefine types to mirror the associated set types. 227 typedef typename S::_ElementType ElementType; 228 typedef typename S::_KeyType KeyType; 229 230 public: 231 explicit InvalSetIterator(S* inval_set); 232 ~InvalSetIterator(); 233 234 ElementType* Current() const; 235 void Advance(); 236 bool Done() const; 237 238 // Mark this iterator as 'done'. 239 void Finish(); 240 241 // Delete the current element and advance the iterator to point to the next 242 // element. 243 void DeleteCurrentAndAdvance(); 244 245 static bool IsValid(const ElementType& element); 246 static KeyType Key(const ElementType& element); 247 248 protected: 249 void MoveToValidElement(); 250 251 // Indicates if the iterator is looking at the vector or at the preallocated 252 // elements. 253 const bool using_vector_; 254 // Used when looking at the preallocated elements, or in debug mode when using 255 // the vector to track how many times the iterator has advanced. 256 size_t index_; 257 typename std::vector<ElementType>::iterator iterator_; 258 S* inval_set_; 259}; 260 261 262template<TEMPLATE_INVALSET_P_DECL> 263InvalSet<TEMPLATE_INVALSET_P_DEF>::InvalSet() 264 : valid_cached_min_(false), 265 sorted_(true), size_(0), vector_(NULL) { 266#ifdef VIXL_DEBUG 267 monitor_ = 0; 268#endif 269} 270 271 272template<TEMPLATE_INVALSET_P_DECL> 273InvalSet<TEMPLATE_INVALSET_P_DEF>::~InvalSet() { 274 VIXL_ASSERT(monitor_ == 0); 275 delete vector_; 276} 277 278 279template<TEMPLATE_INVALSET_P_DECL> 280void InvalSet<TEMPLATE_INVALSET_P_DEF>::insert(const ElementType& element) { 281 VIXL_ASSERT(monitor() == 0); 282 VIXL_ASSERT(IsValid(element)); 283 VIXL_ASSERT(Search(element) == NULL); 284 set_sorted(empty() || (sorted_ && (element > CleanBack()))); 285 if (IsUsingVector()) { 286 vector_->push_back(element); 287 } else { 288 if (size_ < kNPreallocatedElements) { 289 preallocated_[size_] = element; 290 } else { 291 // Transition to using the vector. 292 vector_ = new std::vector<ElementType>(preallocated_, 293 preallocated_ + size_); 294 vector_->push_back(element); 295 } 296 } 297 size_++; 298 299 if (valid_cached_min_ && (element < min_element())) { 300 cached_min_index_ = IsUsingVector() ? vector_->size() - 1 : size_ - 1; 301 cached_min_key_ = Key(element); 302 valid_cached_min_ = true; 303 } 304 305 if (ShouldReclaimMemory()) { 306 ReclaimMemory(); 307 } 308} 309 310 311template<TEMPLATE_INVALSET_P_DECL> 312void InvalSet<TEMPLATE_INVALSET_P_DEF>::erase(const ElementType& element) { 313 VIXL_ASSERT(monitor() == 0); 314 VIXL_ASSERT(IsValid(element)); 315 ElementType* local_element = Search(element); 316 if (local_element != NULL) { 317 EraseInternal(local_element); 318 } 319} 320 321 322template<TEMPLATE_INVALSET_P_DECL> 323ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::Search( 324 const ElementType& element) { 325 VIXL_ASSERT(monitor() == 0); 326 if (empty()) { 327 return NULL; 328 } 329 if (ShouldReclaimMemory()) { 330 ReclaimMemory(); 331 } 332 if (!sorted_) { 333 Sort(kHardSort); 334 } 335 if (!valid_cached_min_) { 336 CacheMinElement(); 337 } 338 return BinarySearch(element, ElementAt(cached_min_index_), StorageEnd()); 339} 340 341 342template<TEMPLATE_INVALSET_P_DECL> 343size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::size() const { 344 return size_; 345} 346 347 348template<TEMPLATE_INVALSET_P_DECL> 349bool InvalSet<TEMPLATE_INVALSET_P_DEF>::empty() const { 350 return size_ == 0; 351} 352 353 354template<TEMPLATE_INVALSET_P_DECL> 355void InvalSet<TEMPLATE_INVALSET_P_DEF>::clear() { 356 VIXL_ASSERT(monitor() == 0); 357 size_ = 0; 358 if (IsUsingVector()) { 359 vector_->clear(); 360 } 361 set_sorted(true); 362 valid_cached_min_ = false; 363} 364 365 366template<TEMPLATE_INVALSET_P_DECL> 367const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::min_element() { 368 VIXL_ASSERT(monitor() == 0); 369 VIXL_ASSERT(!empty()); 370 CacheMinElement(); 371 return *ElementAt(cached_min_index_); 372} 373 374 375template<TEMPLATE_INVALSET_P_DECL> 376KeyType InvalSet<TEMPLATE_INVALSET_P_DEF>::min_element_key() { 377 VIXL_ASSERT(monitor() == 0); 378 if (valid_cached_min_) { 379 return cached_min_key_; 380 } else { 381 return Key(min_element()); 382 } 383} 384 385 386template<TEMPLATE_INVALSET_P_DECL> 387bool InvalSet<TEMPLATE_INVALSET_P_DEF>::IsValid(const ElementType& element) { 388 return Key(element) != kInvalidKey; 389} 390 391 392template<TEMPLATE_INVALSET_P_DECL> 393void InvalSet<TEMPLATE_INVALSET_P_DEF>::EraseInternal(ElementType* element) { 394 // Note that this function must be safe even while an iterator has acquired 395 // this set. 396 VIXL_ASSERT(element != NULL); 397 size_t deleted_index = ElementIndex(element); 398 if (IsUsingVector()) { 399 VIXL_ASSERT((&(vector_->front()) <= element) && 400 (element <= &(vector_->back()))); 401 SetKey(element, kInvalidKey); 402 } else { 403 VIXL_ASSERT((preallocated_ <= element) && 404 (element < (preallocated_ + kNPreallocatedElements))); 405 ElementType* end = preallocated_ + kNPreallocatedElements; 406 size_t copy_size = sizeof(*element) * (end - element - 1); 407 memmove(element, element + 1, copy_size); 408 } 409 size_--; 410 411 if (valid_cached_min_ && 412 (deleted_index == cached_min_index_)) { 413 if (sorted_ && !empty()) { 414 const ElementType* min = FirstValidElement(element, StorageEnd()); 415 cached_min_index_ = ElementIndex(min); 416 cached_min_key_ = Key(*min); 417 valid_cached_min_ = true; 418 } else { 419 valid_cached_min_ = false; 420 } 421 } 422} 423 424 425template<TEMPLATE_INVALSET_P_DECL> 426ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::BinarySearch( 427 const ElementType& element, ElementType* start, ElementType* end) const { 428 if (start == end) { 429 return NULL; 430 } 431 VIXL_ASSERT(sorted_); 432 VIXL_ASSERT(start < end); 433 VIXL_ASSERT(!empty()); 434 435 // Perform a binary search through the elements while ignoring invalid 436 // elements. 437 ElementType* elements = start; 438 size_t low = 0; 439 size_t high = (end - start) - 1; 440 while (low < high) { 441 // Find valid bounds. 442 while (!IsValid(elements[low]) && (low < high)) ++low; 443 while (!IsValid(elements[high]) && (low < high)) --high; 444 VIXL_ASSERT(low <= high); 445 // Avoid overflow when computing the middle index. 446 size_t middle = low / 2 + high / 2 + (low & high & 1); 447 if ((middle == low) || (middle == high)) { 448 break; 449 } 450 while (!IsValid(elements[middle]) && (middle < high - 1)) ++middle; 451 while (!IsValid(elements[middle]) && (low + 1 < middle)) --middle; 452 if (!IsValid(elements[middle])) { 453 break; 454 } 455 if (elements[middle] < element) { 456 low = middle; 457 } else { 458 high = middle; 459 } 460 } 461 462 if (elements[low] == element) return &elements[low]; 463 if (elements[high] == element) return &elements[high]; 464 return NULL; 465} 466 467 468template<TEMPLATE_INVALSET_P_DECL> 469void InvalSet<TEMPLATE_INVALSET_P_DEF>::Sort(SortType sort_type) { 470 VIXL_ASSERT(monitor() == 0); 471 if (sort_type == kSoftSort) { 472 if (sorted_) { 473 return; 474 } 475 } 476 if (empty()) { 477 return; 478 } 479 480 Clean(); 481 std::sort(StorageBegin(), StorageEnd()); 482 483 set_sorted(true); 484 cached_min_index_ = 0; 485 cached_min_key_ = Key(Front()); 486 valid_cached_min_ = true; 487} 488 489 490template<TEMPLATE_INVALSET_P_DECL> 491void InvalSet<TEMPLATE_INVALSET_P_DEF>::Clean() { 492 VIXL_ASSERT(monitor() == 0); 493 if (empty() || !IsUsingVector()) { 494 return; 495 } 496 // Manually iterate through the vector storage to discard invalid elements. 497 ElementType* start = &(vector_->front()); 498 ElementType* end = start + vector_->size(); 499 ElementType* c = start; 500 ElementType* first_invalid; 501 ElementType* first_valid; 502 ElementType* next_invalid; 503 504 while (c < end && IsValid(*c)) { c++; } 505 first_invalid = c; 506 507 while (c < end) { 508 while (c < end && !IsValid(*c)) { c++; } 509 first_valid = c; 510 while (c < end && IsValid(*c)) { c++; } 511 next_invalid = c; 512 513 ptrdiff_t n_moved_elements = (next_invalid - first_valid); 514 memmove(first_invalid, first_valid, n_moved_elements * sizeof(*c)); 515 first_invalid = first_invalid + n_moved_elements; 516 c = next_invalid; 517 } 518 519 // Delete the trailing invalid elements. 520 vector_->erase(vector_->begin() + (first_invalid - start), vector_->end()); 521 VIXL_ASSERT(vector_->size() == size_); 522 523 if (sorted_) { 524 valid_cached_min_ = true; 525 cached_min_index_ = 0; 526 cached_min_key_ = Key(*ElementAt(0)); 527 } else { 528 valid_cached_min_ = false; 529 } 530} 531 532 533template<TEMPLATE_INVALSET_P_DECL> 534const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Front() const { 535 VIXL_ASSERT(!empty()); 536 return IsUsingVector() ? vector_->front() : preallocated_[0]; 537} 538 539 540template<TEMPLATE_INVALSET_P_DECL> 541const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Back() const { 542 VIXL_ASSERT(!empty()); 543 return IsUsingVector() ? vector_->back() : preallocated_[size_ - 1]; 544} 545 546 547template<TEMPLATE_INVALSET_P_DECL> 548const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::CleanBack() { 549 VIXL_ASSERT(monitor() == 0); 550 if (IsUsingVector()) { 551 // Delete the invalid trailing elements. 552 typename std::vector<ElementType>::reverse_iterator it = vector_->rbegin(); 553 while (!IsValid(*it)) { 554 it++; 555 } 556 vector_->erase(it.base(), vector_->end()); 557 } 558 return Back(); 559} 560 561 562template<TEMPLATE_INVALSET_P_DECL> 563const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() const { 564 return IsUsingVector() ? &(vector_->front()) : preallocated_; 565} 566 567 568template<TEMPLATE_INVALSET_P_DECL> 569const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() const { 570 return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_; 571} 572 573 574template<TEMPLATE_INVALSET_P_DECL> 575ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() { 576 return IsUsingVector() ? &(vector_->front()) : preallocated_; 577} 578 579 580template<TEMPLATE_INVALSET_P_DECL> 581ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() { 582 return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_; 583} 584 585 586template<TEMPLATE_INVALSET_P_DECL> 587size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::ElementIndex( 588 const ElementType* element) const { 589 VIXL_ASSERT((StorageBegin() <= element) && (element < StorageEnd())); 590 return element - StorageBegin(); 591} 592 593 594template<TEMPLATE_INVALSET_P_DECL> 595const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::ElementAt( 596 size_t index) const { 597 VIXL_ASSERT( 598 (IsUsingVector() && (index < vector_->size())) || (index < size_)); 599 return StorageBegin() + index; 600} 601 602template<TEMPLATE_INVALSET_P_DECL> 603ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::ElementAt(size_t index) { 604 VIXL_ASSERT( 605 (IsUsingVector() && (index < vector_->size())) || (index < size_)); 606 return StorageBegin() + index; 607} 608 609template<TEMPLATE_INVALSET_P_DECL> 610const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::FirstValidElement( 611 const ElementType* from, const ElementType* end) { 612 while ((from < end) && !IsValid(*from)) { 613 from++; 614 } 615 return from; 616} 617 618 619template<TEMPLATE_INVALSET_P_DECL> 620void InvalSet<TEMPLATE_INVALSET_P_DEF>::CacheMinElement() { 621 VIXL_ASSERT(monitor() == 0); 622 VIXL_ASSERT(!empty()); 623 624 if (valid_cached_min_) { 625 return; 626 } 627 628 if (sorted_) { 629 const ElementType* min = FirstValidElement(StorageBegin(), StorageEnd()); 630 cached_min_index_ = ElementIndex(min); 631 cached_min_key_ = Key(*min); 632 valid_cached_min_ = true; 633 } else { 634 Sort(kHardSort); 635 } 636 VIXL_ASSERT(valid_cached_min_); 637} 638 639 640template<TEMPLATE_INVALSET_P_DECL> 641bool InvalSet<TEMPLATE_INVALSET_P_DEF>::ShouldReclaimMemory() const { 642 if (!IsUsingVector()) { 643 return false; 644 } 645 size_t n_invalid_elements = vector_->size() - size_; 646 return (n_invalid_elements > RECLAIM_FROM) && 647 (n_invalid_elements > vector_->size() / RECLAIM_FACTOR); 648} 649 650 651template<TEMPLATE_INVALSET_P_DECL> 652void InvalSet<TEMPLATE_INVALSET_P_DEF>::ReclaimMemory() { 653 VIXL_ASSERT(monitor() == 0); 654 Clean(); 655} 656 657 658template<class S> 659InvalSetIterator<S>::InvalSetIterator(S* inval_set) 660 : using_vector_((inval_set != NULL) && inval_set->IsUsingVector()), 661 index_(0), 662 inval_set_(inval_set) { 663 if (inval_set != NULL) { 664 inval_set->Sort(S::kSoftSort); 665#ifdef VIXL_DEBUG 666 inval_set->Acquire(); 667#endif 668 if (using_vector_) { 669 iterator_ = typename std::vector<ElementType>::iterator( 670 inval_set_->vector_->begin()); 671 } 672 MoveToValidElement(); 673 } 674} 675 676 677template<class S> 678InvalSetIterator<S>::~InvalSetIterator() { 679#ifdef VIXL_DEBUG 680 if (inval_set_ != NULL) { 681 inval_set_->Release(); 682 } 683#endif 684} 685 686 687template<class S> 688typename S::_ElementType* InvalSetIterator<S>::Current() const { 689 VIXL_ASSERT(!Done()); 690 if (using_vector_) { 691 return &(*iterator_); 692 } else { 693 return &(inval_set_->preallocated_[index_]); 694 } 695} 696 697 698template<class S> 699void InvalSetIterator<S>::Advance() { 700 VIXL_ASSERT(!Done()); 701 if (using_vector_) { 702 iterator_++; 703#ifdef VIXL_DEBUG 704 index_++; 705#endif 706 MoveToValidElement(); 707 } else { 708 index_++; 709 } 710} 711 712 713template<class S> 714bool InvalSetIterator<S>::Done() const { 715 if (using_vector_) { 716 bool done = (iterator_ == inval_set_->vector_->end()); 717 VIXL_ASSERT(done == (index_ == inval_set_->size())); 718 return done; 719 } else { 720 return index_ == inval_set_->size(); 721 } 722} 723 724 725template<class S> 726void InvalSetIterator<S>::Finish() { 727 VIXL_ASSERT(inval_set_->sorted_); 728 if (using_vector_) { 729 iterator_ = inval_set_->vector_->end(); 730 } 731 index_ = inval_set_->size(); 732} 733 734 735template<class S> 736void InvalSetIterator<S>::DeleteCurrentAndAdvance() { 737 if (using_vector_) { 738 inval_set_->EraseInternal(&(*iterator_)); 739 MoveToValidElement(); 740 } else { 741 inval_set_->EraseInternal(inval_set_->preallocated_ + index_); 742 } 743} 744 745 746template<class S> 747bool InvalSetIterator<S>::IsValid(const ElementType& element) { 748 return S::IsValid(element); 749} 750 751 752template<class S> 753typename S::_KeyType InvalSetIterator<S>::Key(const ElementType& element) { 754 return S::Key(element); 755} 756 757 758template<class S> 759void InvalSetIterator<S>::MoveToValidElement() { 760 if (using_vector_) { 761 while ((iterator_ != inval_set_->vector_->end()) && !IsValid(*iterator_)) { 762 iterator_++; 763 } 764 } else { 765 VIXL_ASSERT(inval_set_->empty() || IsValid(inval_set_->preallocated_[0])); 766 // Nothing to do. 767 } 768} 769 770#undef TEMPLATE_INVALSET_P_DECL 771#undef TEMPLATE_INVALSET_P_DEF 772 773} // namespace vixl 774 775#endif // VIXL_INVALSET_H_