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