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