xref: /third_party/vixl/src/invalset-vixl.h (revision b8021494)
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
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#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
199  bool IsUsingVector() const { return vector_ != NULL; }
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
234  int monitor() const { return monitor_; }
235  void Acquire() { monitor_++; }
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
257template <class S>
258class 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
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
333template <TEMPLATE_INVALSET_P_DECL>
334InvalSet<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
341template <TEMPLATE_INVALSET_P_DECL>
342InvalSet<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
350template <TEMPLATE_INVALSET_P_DECL>
351InvalSet<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
360template <TEMPLATE_INVALSET_P_DECL>
361typename InvalSet<TEMPLATE_INVALSET_P_DEF>::iterator
362InvalSet<TEMPLATE_INVALSET_P_DEF>::begin() {
363  return iterator(this);
364}
365
366
367template <TEMPLATE_INVALSET_P_DECL>
368typename InvalSet<TEMPLATE_INVALSET_P_DEF>::iterator
369InvalSet<TEMPLATE_INVALSET_P_DEF>::end() {
370  iterator end(this);
371  end.Finish();
372  return end;
373}
374
375
376template <TEMPLATE_INVALSET_P_DECL>
377void 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
413template <TEMPLATE_INVALSET_P_DECL>
414size_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
426template <TEMPLATE_INVALSET_P_DECL>
427ElementType* 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
446template <TEMPLATE_INVALSET_P_DECL>
447size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::size() const {
448  return size_;
449}
450
451
452template <TEMPLATE_INVALSET_P_DECL>
453bool InvalSet<TEMPLATE_INVALSET_P_DEF>::empty() const {
454  return size_ == 0;
455}
456
457
458template <TEMPLATE_INVALSET_P_DECL>
459void 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
470template <TEMPLATE_INVALSET_P_DECL>
471const 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
479template <TEMPLATE_INVALSET_P_DECL>
480KeyType 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
490template <TEMPLATE_INVALSET_P_DECL>
491bool InvalSet<TEMPLATE_INVALSET_P_DEF>::IsValid(const ElementType& element) {
492  return GetKey(element) != kInvalidKey;
493}
494
495
496template <TEMPLATE_INVALSET_P_DECL>
497void 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
528template <TEMPLATE_INVALSET_P_DECL>
529ElementType* 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
571template <TEMPLATE_INVALSET_P_DECL>
572void 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
593template <TEMPLATE_INVALSET_P_DECL>
594void 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
636template <TEMPLATE_INVALSET_P_DECL>
637const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Front() const {
638  VIXL_ASSERT(!empty());
639  return IsUsingVector() ? vector_->front() : preallocated_[0];
640}
641
642
643template <TEMPLATE_INVALSET_P_DECL>
644const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Back() const {
645  VIXL_ASSERT(!empty());
646  return IsUsingVector() ? vector_->back() : preallocated_[size_ - 1];
647}
648
649
650template <TEMPLATE_INVALSET_P_DECL>
651const 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
665template <TEMPLATE_INVALSET_P_DECL>
666const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() const {
667  return IsUsingVector() ? &(vector_->front()) : preallocated_;
668}
669
670
671template <TEMPLATE_INVALSET_P_DECL>
672const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() const {
673  return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_;
674}
675
676
677template <TEMPLATE_INVALSET_P_DECL>
678ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() {
679  return IsUsingVector() ? &(vector_->front()) : preallocated_;
680}
681
682
683template <TEMPLATE_INVALSET_P_DECL>
684ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() {
685  return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_;
686}
687
688
689template <TEMPLATE_INVALSET_P_DECL>
690size_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
697template <TEMPLATE_INVALSET_P_DECL>
698const 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
705template <TEMPLATE_INVALSET_P_DECL>
706ElementType* 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
712template <TEMPLATE_INVALSET_P_DECL>
713const 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
722template <TEMPLATE_INVALSET_P_DECL>
723void 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
743template <TEMPLATE_INVALSET_P_DECL>
744bool 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
754template <TEMPLATE_INVALSET_P_DECL>
755void InvalSet<TEMPLATE_INVALSET_P_DEF>::ReclaimMemory() {
756  VIXL_ASSERT(monitor() == 0);
757  Clean();
758}
759
760
761template <class S>
762InvalSetIterator<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
785template <class S>
786InvalSetIterator<S>::~InvalSetIterator() {
787#ifdef VIXL_DEBUG
788  if (inval_set_ != NULL) inval_set_->Release();
789#endif
790}
791
792
793template <class S>
794typename 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
804template <class S>
805void InvalSetIterator<S>::Advance() {
806  ++(*this);
807}
808
809
810template <class S>
811bool 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
822template <class S>
823void 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
832template <class S>
833void 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
843template <class S>
844bool InvalSetIterator<S>::IsValid(const ElementType& element) {
845  return S::IsValid(element);
846}
847
848
849template <class S>
850typename S::_KeyType InvalSetIterator<S>::GetKey(const ElementType& element) {
851  return S::GetKey(element);
852}
853
854
855template <class S>
856void 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
868template <class S>
869InvalSetIterator<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
881template <class S>
882InvalSetIterator<S>::InvalSetIterator(InvalSetIterator<S>&& other) noexcept
883    : using_vector_(false), index_(0), inval_set_(NULL) {
884  swap(*this, other);
885}
886#endif
887
888
889template <class S>
890InvalSetIterator<S>& InvalSetIterator<S>::operator=(InvalSetIterator<S> other) {
891  swap(*this, other);
892  return *this;
893}
894
895
896template <class S>
897bool 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
924template <class S>
925InvalSetIterator<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
941template <class S>
942InvalSetIterator<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