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
37namespace vixl {
38
39// We define a custom data structure template and its iterator as `std`
40// containers do not fit the performance requirements for some of our use cases.
41//
42// The structure behaves like an iterable unordered set with special properties
43// and restrictions. "InvalSet" stands for "Invalidatable Set".
44//
45// Restrictions and requirements:
46// - Adding an element already present in the set is illegal. In debug mode,
47//   this is checked at insertion time.
48// - The templated class `ElementType` must provide comparison operators so that
49//   `std::sort()` can be used.
50// - A key must be available to represent invalid elements.
51// - Elements with an invalid key must compare higher or equal to any other
52//   element.
53//
54// Use cases and performance considerations:
55// Our use cases present two specificities that allow us to design this
56// structure to provide fast insertion *and* fast search and deletion
57// operations:
58// - Elements are (generally) inserted in order (sorted according to their key).
59// - A key is available to mark elements as invalid (deleted).
60// The backing `std::vector` allows for fast insertions. When
61// searching for an element we ensure the elements are sorted (this is generally
62// the case) and perform a binary search. When deleting an element we do not
63// free the associated memory immediately. Instead, an element to be deleted is
64// marked with the 'invalid' key. Other methods of the container take care of
65// ignoring entries marked as invalid.
66// To avoid the overhead of the `std::vector` container when only few entries
67// are used, a number of elements are preallocated.
68
69// 'ElementType' and 'KeyType' are respectively the types of the elements and
70// their key. The structure only reclaims memory when safe to do so, if the
71// number of elements that can be reclaimed is greater than `RECLAIM_FROM` and
72// greater than `<total number of elements> / RECLAIM_FACTOR.
73// 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
87template <class S>
88class InvalSetIterator;  // Forward declaration.
89
90template <TEMPLATE_INVALSET_P_DECL>
91class InvalSet {
92 public:
93  InvalSet();
94  ~InvalSet();
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
193  bool IsUsingVector() const { return vector_ != NULL; }
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
223  int monitor() const { return monitor_; }
224  void Acquire() { monitor_++; }
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
246template <class S>
247class 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
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
316template <TEMPLATE_INVALSET_P_DECL>
317InvalSet<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
325template <TEMPLATE_INVALSET_P_DECL>
326InvalSet<TEMPLATE_INVALSET_P_DEF>::~InvalSet() {
327  VIXL_ASSERT(monitor_ == 0);
328  delete vector_;
329}
330
331
332template <TEMPLATE_INVALSET_P_DECL>
333typename InvalSet<TEMPLATE_INVALSET_P_DEF>::iterator
334InvalSet<TEMPLATE_INVALSET_P_DEF>::begin() {
335  return iterator(this);
336}
337
338
339template <TEMPLATE_INVALSET_P_DECL>
340typename InvalSet<TEMPLATE_INVALSET_P_DEF>::iterator
341InvalSet<TEMPLATE_INVALSET_P_DEF>::end() {
342  iterator end(this);
343  end.Finish();
344  return end;
345}
346
347
348template <TEMPLATE_INVALSET_P_DECL>
349void InvalSet<TEMPLATE_INVALSET_P_DEF>::insert(const ElementType& element) {
350  VIXL_ASSERT(monitor() == 0);
351  VIXL_ASSERT(IsValid(element));
352  VIXL_ASSERT(Search(element) == NULL);
353  SetSorted(empty() || (sorted_ && (element > CleanBack())));
354  if (IsUsingVector()) {
355    vector_->push_back(element);
356  } else {
357    if (size_ < kNPreallocatedElements) {
358      preallocated_[size_] = element;
359    } else {
360      // Transition to using the vector.
361      vector_ =
362          new std::vector<ElementType>(preallocated_, preallocated_ + size_);
363      vector_->push_back(element);
364    }
365  }
366  size_++;
367
368  if (valid_cached_min_ && (element < GetMinElement())) {
369    cached_min_index_ = IsUsingVector() ? vector_->size() - 1 : size_ - 1;
370    cached_min_key_ = GetKey(element);
371    valid_cached_min_ = true;
372  }
373
374  if (ShouldReclaimMemory()) {
375    ReclaimMemory();
376  }
377}
378
379
380template <TEMPLATE_INVALSET_P_DECL>
381size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::erase(const ElementType& element) {
382  VIXL_ASSERT(monitor() == 0);
383  VIXL_ASSERT(IsValid(element));
384  ElementType* local_element = Search(element);
385  if (local_element != NULL) {
386    EraseInternal(local_element);
387    return 1;
388  }
389  return 0;
390}
391
392
393template <TEMPLATE_INVALSET_P_DECL>
394ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::Search(
395    const ElementType& element) {
396  VIXL_ASSERT(monitor() == 0);
397  if (empty()) {
398    return NULL;
399  }
400  if (ShouldReclaimMemory()) {
401    ReclaimMemory();
402  }
403  if (!sorted_) {
404    Sort(kHardSort);
405  }
406  if (!valid_cached_min_) {
407    CacheMinElement();
408  }
409  return BinarySearch(element, GetElementAt(cached_min_index_), StorageEnd());
410}
411
412
413template <TEMPLATE_INVALSET_P_DECL>
414size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::size() const {
415  return size_;
416}
417
418
419template <TEMPLATE_INVALSET_P_DECL>
420bool InvalSet<TEMPLATE_INVALSET_P_DEF>::empty() const {
421  return size_ == 0;
422}
423
424
425template <TEMPLATE_INVALSET_P_DECL>
426void InvalSet<TEMPLATE_INVALSET_P_DEF>::clear() {
427  VIXL_ASSERT(monitor() == 0);
428  size_ = 0;
429  if (IsUsingVector()) {
430    vector_->clear();
431  }
432  SetSorted(true);
433  valid_cached_min_ = false;
434}
435
436
437template <TEMPLATE_INVALSET_P_DECL>
438const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::GetMinElement() {
439  VIXL_ASSERT(monitor() == 0);
440  VIXL_ASSERT(!empty());
441  CacheMinElement();
442  return *GetElementAt(cached_min_index_);
443}
444
445
446template <TEMPLATE_INVALSET_P_DECL>
447KeyType InvalSet<TEMPLATE_INVALSET_P_DEF>::GetMinElementKey() {
448  VIXL_ASSERT(monitor() == 0);
449  if (valid_cached_min_) {
450    return cached_min_key_;
451  } else {
452    return GetKey(GetMinElement());
453  }
454}
455
456
457template <TEMPLATE_INVALSET_P_DECL>
458bool InvalSet<TEMPLATE_INVALSET_P_DEF>::IsValid(const ElementType& element) {
459  return GetKey(element) != kInvalidKey;
460}
461
462
463template <TEMPLATE_INVALSET_P_DECL>
464void InvalSet<TEMPLATE_INVALSET_P_DEF>::EraseInternal(ElementType* element) {
465  // Note that this function must be safe even while an iterator has acquired
466  // this set.
467  VIXL_ASSERT(element != NULL);
468  size_t deleted_index = GetElementIndex(element);
469  if (IsUsingVector()) {
470    VIXL_ASSERT((&(vector_->front()) <= element) &&
471                (element <= &(vector_->back())));
472    SetKey(element, kInvalidKey);
473  } else {
474    VIXL_ASSERT((preallocated_ <= element) &&
475                (element < (preallocated_ + kNPreallocatedElements)));
476    ElementType* end = preallocated_ + kNPreallocatedElements;
477    size_t copy_size = sizeof(*element) * (end - element - 1);
478    memmove(element, element + 1, copy_size);
479  }
480  size_--;
481
482  if (valid_cached_min_ && (deleted_index == cached_min_index_)) {
483    if (sorted_ && !empty()) {
484      const ElementType* min = GetFirstValidElement(element, StorageEnd());
485      cached_min_index_ = GetElementIndex(min);
486      cached_min_key_ = GetKey(*min);
487      valid_cached_min_ = true;
488    } else {
489      valid_cached_min_ = false;
490    }
491  }
492}
493
494
495template <TEMPLATE_INVALSET_P_DECL>
496ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::BinarySearch(
497    const ElementType& element, ElementType* start, ElementType* end) const {
498  if (start == end) {
499    return NULL;
500  }
501  VIXL_ASSERT(sorted_);
502  VIXL_ASSERT(start < end);
503  VIXL_ASSERT(!empty());
504
505  // Perform a binary search through the elements while ignoring invalid
506  // elements.
507  ElementType* elements = start;
508  size_t low = 0;
509  size_t high = (end - start) - 1;
510  while (low < high) {
511    // Find valid bounds.
512    while (!IsValid(elements[low]) && (low < high)) ++low;
513    while (!IsValid(elements[high]) && (low < high)) --high;
514    VIXL_ASSERT(low <= high);
515    // Avoid overflow when computing the middle index.
516    size_t middle = low + (high - low) / 2;
517    if ((middle == low) || (middle == high)) {
518      break;
519    }
520    while ((middle < high - 1) && !IsValid(elements[middle])) ++middle;
521    while ((low + 1 < middle) && !IsValid(elements[middle])) --middle;
522    if (!IsValid(elements[middle])) {
523      break;
524    }
525    if (elements[middle] < element) {
526      low = middle;
527    } else {
528      high = middle;
529    }
530  }
531
532  if (elements[low] == element) return &elements[low];
533  if (elements[high] == element) return &elements[high];
534  return NULL;
535}
536
537
538template <TEMPLATE_INVALSET_P_DECL>
539void InvalSet<TEMPLATE_INVALSET_P_DEF>::Sort(SortType sort_type) {
540  if (sort_type == kSoftSort) {
541    if (sorted_) {
542      return;
543    }
544  }
545  VIXL_ASSERT(monitor() == 0);
546  if (empty()) {
547    return;
548  }
549
550  Clean();
551  std::sort(StorageBegin(), StorageEnd());
552
553  SetSorted(true);
554  cached_min_index_ = 0;
555  cached_min_key_ = GetKey(Front());
556  valid_cached_min_ = true;
557}
558
559
560template <TEMPLATE_INVALSET_P_DECL>
561void InvalSet<TEMPLATE_INVALSET_P_DEF>::Clean() {
562  VIXL_ASSERT(monitor() == 0);
563  if (empty() || !IsUsingVector()) {
564    return;
565  }
566  // Manually iterate through the vector storage to discard invalid elements.
567  ElementType* start = &(vector_->front());
568  ElementType* end = start + vector_->size();
569  ElementType* c = start;
570  ElementType* first_invalid;
571  ElementType* first_valid;
572  ElementType* next_invalid;
573
574  while ((c < end) && IsValid(*c)) c++;
575  first_invalid = c;
576
577  while (c < end) {
578    while ((c < end) && !IsValid(*c)) c++;
579    first_valid = c;
580    while ((c < end) && IsValid(*c)) c++;
581    next_invalid = c;
582
583    ptrdiff_t n_moved_elements = (next_invalid - first_valid);
584    memmove(first_invalid, first_valid, n_moved_elements * sizeof(*c));
585    first_invalid = first_invalid + n_moved_elements;
586    c = next_invalid;
587  }
588
589  // Delete the trailing invalid elements.
590  vector_->erase(vector_->begin() + (first_invalid - start), vector_->end());
591  VIXL_ASSERT(vector_->size() == size_);
592
593  if (sorted_) {
594    valid_cached_min_ = true;
595    cached_min_index_ = 0;
596    cached_min_key_ = GetKey(*GetElementAt(0));
597  } else {
598    valid_cached_min_ = false;
599  }
600}
601
602
603template <TEMPLATE_INVALSET_P_DECL>
604const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Front() const {
605  VIXL_ASSERT(!empty());
606  return IsUsingVector() ? vector_->front() : preallocated_[0];
607}
608
609
610template <TEMPLATE_INVALSET_P_DECL>
611const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Back() const {
612  VIXL_ASSERT(!empty());
613  return IsUsingVector() ? vector_->back() : preallocated_[size_ - 1];
614}
615
616
617template <TEMPLATE_INVALSET_P_DECL>
618const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::CleanBack() {
619  VIXL_ASSERT(monitor() == 0);
620  if (IsUsingVector()) {
621    // Delete the invalid trailing elements.
622    typename std::vector<ElementType>::reverse_iterator it = vector_->rbegin();
623    while (!IsValid(*it)) {
624      it++;
625    }
626    vector_->erase(it.base(), vector_->end());
627  }
628  return Back();
629}
630
631
632template <TEMPLATE_INVALSET_P_DECL>
633const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() const {
634  return IsUsingVector() ? &(vector_->front()) : preallocated_;
635}
636
637
638template <TEMPLATE_INVALSET_P_DECL>
639const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() const {
640  return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_;
641}
642
643
644template <TEMPLATE_INVALSET_P_DECL>
645ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() {
646  return IsUsingVector() ? &(vector_->front()) : preallocated_;
647}
648
649
650template <TEMPLATE_INVALSET_P_DECL>
651ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() {
652  return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_;
653}
654
655
656template <TEMPLATE_INVALSET_P_DECL>
657size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::GetElementIndex(
658    const ElementType* element) const {
659  VIXL_ASSERT((StorageBegin() <= element) && (element < StorageEnd()));
660  return element - StorageBegin();
661}
662
663
664template <TEMPLATE_INVALSET_P_DECL>
665const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::GetElementAt(
666    size_t index) const {
667  VIXL_ASSERT((IsUsingVector() && (index < vector_->size())) ||
668              (index < size_));
669  return StorageBegin() + index;
670}
671
672template <TEMPLATE_INVALSET_P_DECL>
673ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::GetElementAt(size_t index) {
674  VIXL_ASSERT((IsUsingVector() && (index < vector_->size())) ||
675              (index < size_));
676  return StorageBegin() + index;
677}
678
679template <TEMPLATE_INVALSET_P_DECL>
680const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::GetFirstValidElement(
681    const ElementType* from, const ElementType* end) {
682  while ((from < end) && !IsValid(*from)) {
683    from++;
684  }
685  return from;
686}
687
688
689template <TEMPLATE_INVALSET_P_DECL>
690void InvalSet<TEMPLATE_INVALSET_P_DEF>::CacheMinElement() {
691  VIXL_ASSERT(monitor() == 0);
692  VIXL_ASSERT(!empty());
693
694  if (valid_cached_min_) {
695    return;
696  }
697
698  if (sorted_) {
699    const ElementType* min = GetFirstValidElement(StorageBegin(), StorageEnd());
700    cached_min_index_ = GetElementIndex(min);
701    cached_min_key_ = GetKey(*min);
702    valid_cached_min_ = true;
703  } else {
704    Sort(kHardSort);
705  }
706  VIXL_ASSERT(valid_cached_min_);
707}
708
709
710template <TEMPLATE_INVALSET_P_DECL>
711bool InvalSet<TEMPLATE_INVALSET_P_DEF>::ShouldReclaimMemory() const {
712  if (!IsUsingVector()) {
713    return false;
714  }
715  size_t n_invalid_elements = vector_->size() - size_;
716  return (n_invalid_elements > RECLAIM_FROM) &&
717         (n_invalid_elements > vector_->size() / RECLAIM_FACTOR);
718}
719
720
721template <TEMPLATE_INVALSET_P_DECL>
722void InvalSet<TEMPLATE_INVALSET_P_DEF>::ReclaimMemory() {
723  VIXL_ASSERT(monitor() == 0);
724  Clean();
725}
726
727
728template <class S>
729InvalSetIterator<S>::InvalSetIterator(S* inval_set)
730    : using_vector_((inval_set != NULL) && inval_set->IsUsingVector()),
731      index_(0),
732      inval_set_(inval_set) {
733  if (inval_set != NULL) {
734    inval_set->Sort(S::kSoftSort);
735#ifdef VIXL_DEBUG
736    inval_set->Acquire();
737#endif
738    if (using_vector_) {
739      iterator_ = typename std::vector<ElementType>::iterator(
740          inval_set_->vector_->begin());
741    }
742    MoveToValidElement();
743  }
744}
745
746
747template <class S>
748InvalSetIterator<S>::~InvalSetIterator() {
749#ifdef VIXL_DEBUG
750  if (inval_set_ != NULL) inval_set_->Release();
751#endif
752}
753
754
755template <class S>
756typename S::_ElementType* InvalSetIterator<S>::Current() const {
757  VIXL_ASSERT(!Done());
758  if (using_vector_) {
759    return &(*iterator_);
760  } else {
761    return &(inval_set_->preallocated_[index_]);
762  }
763}
764
765
766template <class S>
767void InvalSetIterator<S>::Advance() {
768  ++(*this);
769}
770
771
772template <class S>
773bool InvalSetIterator<S>::Done() const {
774  if (using_vector_) {
775    bool done = (iterator_ == inval_set_->vector_->end());
776    VIXL_ASSERT(done == (index_ == inval_set_->size()));
777    return done;
778  } else {
779    return index_ == inval_set_->size();
780  }
781}
782
783
784template <class S>
785void InvalSetIterator<S>::Finish() {
786  VIXL_ASSERT(inval_set_->sorted_);
787  if (using_vector_) {
788    iterator_ = inval_set_->vector_->end();
789  }
790  index_ = inval_set_->size();
791}
792
793
794template <class S>
795void InvalSetIterator<S>::DeleteCurrentAndAdvance() {
796  if (using_vector_) {
797    inval_set_->EraseInternal(&(*iterator_));
798    MoveToValidElement();
799  } else {
800    inval_set_->EraseInternal(inval_set_->preallocated_ + index_);
801  }
802}
803
804
805template <class S>
806bool InvalSetIterator<S>::IsValid(const ElementType& element) {
807  return S::IsValid(element);
808}
809
810
811template <class S>
812typename S::_KeyType InvalSetIterator<S>::GetKey(const ElementType& element) {
813  return S::GetKey(element);
814}
815
816
817template <class S>
818void InvalSetIterator<S>::MoveToValidElement() {
819  if (using_vector_) {
820    while ((iterator_ != inval_set_->vector_->end()) && !IsValid(*iterator_)) {
821      iterator_++;
822    }
823  } else {
824    VIXL_ASSERT(inval_set_->empty() || IsValid(inval_set_->preallocated_[0]));
825    // Nothing to do.
826  }
827}
828
829
830template <class S>
831InvalSetIterator<S>::InvalSetIterator(const InvalSetIterator<S>& other)
832    : using_vector_(other.using_vector_),
833      index_(other.index_),
834      inval_set_(other.inval_set_) {
835#ifdef VIXL_DEBUG
836  if (inval_set_ != NULL) inval_set_->Acquire();
837#endif
838}
839
840
841#if __cplusplus >= 201103L
842template <class S>
843InvalSetIterator<S>::InvalSetIterator(InvalSetIterator<S>&& other) noexcept
844    : using_vector_(false),
845      index_(0),
846      inval_set_(NULL) {
847  swap(*this, other);
848}
849#endif
850
851
852template <class S>
853InvalSetIterator<S>& InvalSetIterator<S>::operator=(InvalSetIterator<S> other) {
854  swap(*this, other);
855  return *this;
856}
857
858
859template <class S>
860bool InvalSetIterator<S>::operator==(const InvalSetIterator<S>& rhs) const {
861  bool equal = (inval_set_ == rhs.inval_set_);
862
863  // If the inval_set_ matches, using_vector_ must also match.
864  VIXL_ASSERT(!equal || (using_vector_ == rhs.using_vector_));
865
866  if (using_vector_) {
867    equal = equal && (iterator_ == rhs.iterator_);
868    // In debug mode, index_ is maintained even with using_vector_.
869    VIXL_ASSERT(!equal || (index_ == rhs.index_));
870  } else {
871    equal = equal && (index_ == rhs.index_);
872#ifdef DEBUG
873    // If not using_vector_, iterator_ should be default-initialised.
874    typename std::vector<ElementType>::iterator default_iterator;
875    VIXL_ASSERT(iterator_ == default_iterator);
876    VIXL_ASSERT(rhs.iterator_ == default_iterator);
877#endif
878  }
879  return equal;
880}
881
882
883template <class S>
884InvalSetIterator<S>& InvalSetIterator<S>::operator++() {
885  // Pre-increment.
886  VIXL_ASSERT(!Done());
887  if (using_vector_) {
888    iterator_++;
889#ifdef VIXL_DEBUG
890    index_++;
891#endif
892    MoveToValidElement();
893  } else {
894    index_++;
895  }
896  return *this;
897}
898
899
900template <class S>
901InvalSetIterator<S> InvalSetIterator<S>::operator++(int /* unused */) {
902  // Post-increment.
903  VIXL_ASSERT(!Done());
904  InvalSetIterator<S> old(*this);
905  ++(*this);
906  return old;
907}
908
909
910#undef TEMPLATE_INVALSET_P_DECL
911#undef TEMPLATE_INVALSET_P_DEF
912
913}  // namespace vixl
914
915#endif  // VIXL_INVALSET_H_
916