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