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