cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

invalset.h (23114B)


      1// Copyright 2015, ARM Limited
      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 "vixl/globals.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#define TEMPLATE_INVALSET_P_DECL                                               \
     74  class ElementType,                                                           \
     75  unsigned N_PREALLOCATED_ELEMENTS,                                            \
     76  class KeyType,                                                               \
     77  KeyType INVALID_KEY,                                                         \
     78  size_t RECLAIM_FROM,                                                         \
     79  unsigned RECLAIM_FACTOR
     80
     81#define TEMPLATE_INVALSET_P_DEF                                                \
     82ElementType, N_PREALLOCATED_ELEMENTS,                                          \
     83KeyType, INVALID_KEY, RECLAIM_FROM, RECLAIM_FACTOR
     84
     85template<class S> class InvalSetIterator;  // Forward declaration.
     86
     87template<TEMPLATE_INVALSET_P_DECL> class InvalSet {
     88 public:
     89  InvalSet();
     90  ~InvalSet();
     91
     92  static const size_t kNPreallocatedElements = N_PREALLOCATED_ELEMENTS;
     93  static const KeyType kInvalidKey = INVALID_KEY;
     94
     95  // It is illegal to insert an element already present in the set.
     96  void insert(const ElementType& element);
     97
     98  // Looks for the specified element in the set and - if found - deletes it.
     99  void erase(const ElementType& element);
    100
    101  // This indicates the number of (valid) elements stored in this set.
    102  size_t size() const;
    103
    104  // Returns true if no elements are stored in the set.
    105  // Note that this does not mean the the backing storage is empty: it can still
    106  // contain invalid elements.
    107  bool empty() const;
    108
    109  void clear();
    110
    111  const ElementType min_element();
    112
    113  // This returns the key of the minimum element in the set.
    114  KeyType min_element_key();
    115
    116  static bool IsValid(const ElementType& element);
    117  static KeyType Key(const ElementType& element);
    118  static void SetKey(ElementType* element, KeyType key);
    119
    120 protected:
    121  // Returns a pointer to the element in vector_ if it was found, or NULL
    122  // otherwise.
    123  ElementType* Search(const ElementType& element);
    124
    125  // The argument *must* point to an element stored in *this* set.
    126  // This function is not allowed to move elements in the backing vector
    127  // storage.
    128  void EraseInternal(ElementType* element);
    129
    130  // The elements in the range searched must be sorted.
    131  ElementType* BinarySearch(const ElementType& element,
    132                            ElementType* start,
    133                            ElementType* end) const;
    134
    135  // Sort the elements.
    136  enum SortType {
    137    // The 'hard' version guarantees that invalid elements are moved to the end
    138    // of the container.
    139    kHardSort,
    140    // The 'soft' version only guarantees that the elements will be sorted.
    141    // Invalid elements may still be present anywhere in the set.
    142    kSoftSort
    143  };
    144  void Sort(SortType sort_type);
    145
    146  // Delete the elements that have an invalid key. The complexity is linear
    147  // with the size of the vector.
    148  void Clean();
    149
    150  const ElementType Front() const;
    151  const ElementType Back() const;
    152
    153  // Delete invalid trailing elements and return the last valid element in the
    154  // set.
    155  const ElementType CleanBack();
    156
    157  // Returns a pointer to the start or end of the backing storage.
    158  const ElementType* StorageBegin() const;
    159  const ElementType* StorageEnd() const;
    160  ElementType* StorageBegin();
    161  ElementType* StorageEnd();
    162
    163  // Returns the index of the element within the backing storage. The element
    164  // must belong to the backing storage.
    165  size_t ElementIndex(const ElementType* element) const;
    166
    167  // Returns the element at the specified index in the backing storage.
    168  const ElementType* ElementAt(size_t index) const;
    169  ElementType* ElementAt(size_t index);
    170
    171  static const ElementType* FirstValidElement(const ElementType* from,
    172                                              const ElementType* end);
    173
    174  void CacheMinElement();
    175  const ElementType CachedMinElement() const;
    176
    177  bool ShouldReclaimMemory() const;
    178  void ReclaimMemory();
    179
    180  bool IsUsingVector() const { return vector_ != NULL; }
    181  void set_sorted(bool sorted) { sorted_ = sorted; }
    182
    183  // We cache some data commonly required by users to improve performance.
    184  // We cannot cache pointers to elements as we do not control the backing
    185  // storage.
    186  bool valid_cached_min_;
    187  size_t cached_min_index_;  // Valid iff `valid_cached_min_` is true.
    188  KeyType cached_min_key_;         // Valid iff `valid_cached_min_` is true.
    189
    190  // Indicates whether the elements are sorted.
    191  bool sorted_;
    192
    193  // This represents the number of (valid) elements in this set.
    194  size_t size_;
    195
    196  // The backing storage is either the array of preallocated elements or the
    197  // vector. The structure starts by using the preallocated elements, and
    198  // transitions (permanently) to using the vector once more than
    199  // kNPreallocatedElements are used.
    200  // Elements are only invalidated when using the vector. The preallocated
    201  // storage always only contains valid elements.
    202  ElementType preallocated_[kNPreallocatedElements];
    203  std::vector<ElementType>* vector_;
    204
    205#ifdef VIXL_DEBUG
    206  // Iterators acquire and release this monitor. While a set is acquired,
    207  // certain operations are illegal to ensure that the iterator will
    208  // correctly iterate over the elements in the set.
    209  int monitor_;
    210  int monitor() const { return monitor_; }
    211  void Acquire() { monitor_++; }
    212  void Release() {
    213    monitor_--;
    214    VIXL_ASSERT(monitor_ >= 0);
    215  }
    216#endif
    217
    218  friend class InvalSetIterator<InvalSet<TEMPLATE_INVALSET_P_DEF> >;
    219  typedef ElementType _ElementType;
    220  typedef KeyType _KeyType;
    221};
    222
    223
    224template<class S> class InvalSetIterator {
    225 private:
    226  // Redefine types to mirror the associated set types.
    227  typedef typename S::_ElementType ElementType;
    228  typedef typename S::_KeyType KeyType;
    229
    230 public:
    231  explicit InvalSetIterator(S* inval_set);
    232  ~InvalSetIterator();
    233
    234  ElementType* Current() const;
    235  void Advance();
    236  bool Done() const;
    237
    238  // Mark this iterator as 'done'.
    239  void Finish();
    240
    241  // Delete the current element and advance the iterator to point to the next
    242  // element.
    243  void DeleteCurrentAndAdvance();
    244
    245  static bool IsValid(const ElementType& element);
    246  static KeyType Key(const ElementType& element);
    247
    248 protected:
    249  void MoveToValidElement();
    250
    251  // Indicates if the iterator is looking at the vector or at the preallocated
    252  // elements.
    253  const bool using_vector_;
    254  // Used when looking at the preallocated elements, or in debug mode when using
    255  // the vector to track how many times the iterator has advanced.
    256  size_t index_;
    257  typename std::vector<ElementType>::iterator iterator_;
    258  S* inval_set_;
    259};
    260
    261
    262template<TEMPLATE_INVALSET_P_DECL>
    263InvalSet<TEMPLATE_INVALSET_P_DEF>::InvalSet()
    264  : valid_cached_min_(false),
    265    sorted_(true), size_(0), vector_(NULL) {
    266#ifdef VIXL_DEBUG
    267  monitor_ = 0;
    268#endif
    269}
    270
    271
    272template<TEMPLATE_INVALSET_P_DECL>
    273InvalSet<TEMPLATE_INVALSET_P_DEF>::~InvalSet() {
    274  VIXL_ASSERT(monitor_ == 0);
    275  delete vector_;
    276}
    277
    278
    279template<TEMPLATE_INVALSET_P_DECL>
    280void InvalSet<TEMPLATE_INVALSET_P_DEF>::insert(const ElementType& element) {
    281  VIXL_ASSERT(monitor() == 0);
    282  VIXL_ASSERT(IsValid(element));
    283  VIXL_ASSERT(Search(element) == NULL);
    284  set_sorted(empty() || (sorted_ && (element > CleanBack())));
    285  if (IsUsingVector()) {
    286    vector_->push_back(element);
    287  } else {
    288    if (size_ < kNPreallocatedElements) {
    289      preallocated_[size_] = element;
    290    } else {
    291      // Transition to using the vector.
    292      vector_ = new std::vector<ElementType>(preallocated_,
    293                                             preallocated_ + size_);
    294      vector_->push_back(element);
    295    }
    296  }
    297  size_++;
    298
    299  if (valid_cached_min_ && (element < min_element())) {
    300    cached_min_index_ = IsUsingVector() ? vector_->size() - 1 : size_ - 1;
    301    cached_min_key_ = Key(element);
    302    valid_cached_min_ = true;
    303  }
    304
    305  if (ShouldReclaimMemory()) {
    306    ReclaimMemory();
    307  }
    308}
    309
    310
    311template<TEMPLATE_INVALSET_P_DECL>
    312void InvalSet<TEMPLATE_INVALSET_P_DEF>::erase(const ElementType& element) {
    313  VIXL_ASSERT(monitor() == 0);
    314  VIXL_ASSERT(IsValid(element));
    315  ElementType* local_element = Search(element);
    316  if (local_element != NULL) {
    317    EraseInternal(local_element);
    318  }
    319}
    320
    321
    322template<TEMPLATE_INVALSET_P_DECL>
    323ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::Search(
    324    const ElementType& element) {
    325  VIXL_ASSERT(monitor() == 0);
    326  if (empty()) {
    327    return NULL;
    328  }
    329  if (ShouldReclaimMemory()) {
    330    ReclaimMemory();
    331  }
    332  if (!sorted_) {
    333    Sort(kHardSort);
    334  }
    335  if (!valid_cached_min_) {
    336    CacheMinElement();
    337  }
    338  return BinarySearch(element, ElementAt(cached_min_index_), StorageEnd());
    339}
    340
    341
    342template<TEMPLATE_INVALSET_P_DECL>
    343size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::size() const {
    344  return size_;
    345}
    346
    347
    348template<TEMPLATE_INVALSET_P_DECL>
    349bool InvalSet<TEMPLATE_INVALSET_P_DEF>::empty() const {
    350  return size_ == 0;
    351}
    352
    353
    354template<TEMPLATE_INVALSET_P_DECL>
    355void InvalSet<TEMPLATE_INVALSET_P_DEF>::clear() {
    356  VIXL_ASSERT(monitor() == 0);
    357  size_ = 0;
    358  if (IsUsingVector()) {
    359    vector_->clear();
    360  }
    361  set_sorted(true);
    362  valid_cached_min_ = false;
    363}
    364
    365
    366template<TEMPLATE_INVALSET_P_DECL>
    367const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::min_element() {
    368  VIXL_ASSERT(monitor() == 0);
    369  VIXL_ASSERT(!empty());
    370  CacheMinElement();
    371  return *ElementAt(cached_min_index_);
    372}
    373
    374
    375template<TEMPLATE_INVALSET_P_DECL>
    376KeyType InvalSet<TEMPLATE_INVALSET_P_DEF>::min_element_key() {
    377  VIXL_ASSERT(monitor() == 0);
    378  if (valid_cached_min_) {
    379    return cached_min_key_;
    380  } else {
    381    return Key(min_element());
    382  }
    383}
    384
    385
    386template<TEMPLATE_INVALSET_P_DECL>
    387bool InvalSet<TEMPLATE_INVALSET_P_DEF>::IsValid(const ElementType& element) {
    388  return Key(element) != kInvalidKey;
    389}
    390
    391
    392template<TEMPLATE_INVALSET_P_DECL>
    393void InvalSet<TEMPLATE_INVALSET_P_DEF>::EraseInternal(ElementType* element) {
    394  // Note that this function must be safe even while an iterator has acquired
    395  // this set.
    396  VIXL_ASSERT(element != NULL);
    397  size_t deleted_index = ElementIndex(element);
    398  if (IsUsingVector()) {
    399    VIXL_ASSERT((&(vector_->front()) <= element) &&
    400                (element <= &(vector_->back())));
    401    SetKey(element, kInvalidKey);
    402  } else {
    403    VIXL_ASSERT((preallocated_ <= element) &&
    404                (element < (preallocated_ + kNPreallocatedElements)));
    405    ElementType* end = preallocated_ + kNPreallocatedElements;
    406    size_t copy_size = sizeof(*element) * (end - element - 1);
    407    memmove(element, element + 1, copy_size);
    408  }
    409  size_--;
    410
    411  if (valid_cached_min_ &&
    412      (deleted_index == cached_min_index_)) {
    413    if (sorted_ && !empty()) {
    414      const ElementType* min = FirstValidElement(element, StorageEnd());
    415      cached_min_index_ = ElementIndex(min);
    416      cached_min_key_ = Key(*min);
    417      valid_cached_min_ = true;
    418    } else {
    419      valid_cached_min_ = false;
    420    }
    421  }
    422}
    423
    424
    425template<TEMPLATE_INVALSET_P_DECL>
    426ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::BinarySearch(
    427    const ElementType& element, ElementType* start, ElementType* end) const {
    428  if (start == end) {
    429    return NULL;
    430  }
    431  VIXL_ASSERT(sorted_);
    432  VIXL_ASSERT(start < end);
    433  VIXL_ASSERT(!empty());
    434
    435  // Perform a binary search through the elements while ignoring invalid
    436  // elements.
    437  ElementType* elements = start;
    438  size_t low = 0;
    439  size_t high = (end - start) - 1;
    440  while (low < high) {
    441    // Find valid bounds.
    442    while (!IsValid(elements[low]) && (low < high)) ++low;
    443    while (!IsValid(elements[high]) && (low < high)) --high;
    444    VIXL_ASSERT(low <= high);
    445    // Avoid overflow when computing the middle index.
    446    size_t middle = low / 2 + high / 2 + (low & high & 1);
    447    if ((middle == low) || (middle == high)) {
    448      break;
    449    }
    450    while (!IsValid(elements[middle]) && (middle < high - 1)) ++middle;
    451    while (!IsValid(elements[middle]) && (low + 1 < middle)) --middle;
    452    if (!IsValid(elements[middle])) {
    453      break;
    454    }
    455    if (elements[middle] < element) {
    456      low = middle;
    457    } else {
    458      high = middle;
    459    }
    460  }
    461
    462  if (elements[low] == element) return &elements[low];
    463  if (elements[high] == element) return &elements[high];
    464  return NULL;
    465}
    466
    467
    468template<TEMPLATE_INVALSET_P_DECL>
    469void InvalSet<TEMPLATE_INVALSET_P_DEF>::Sort(SortType sort_type) {
    470  VIXL_ASSERT(monitor() == 0);
    471  if (sort_type == kSoftSort) {
    472    if (sorted_) {
    473      return;
    474    }
    475  }
    476  if (empty()) {
    477    return;
    478  }
    479
    480  Clean();
    481  std::sort(StorageBegin(), StorageEnd());
    482
    483  set_sorted(true);
    484  cached_min_index_ = 0;
    485  cached_min_key_ = Key(Front());
    486  valid_cached_min_ = true;
    487}
    488
    489
    490template<TEMPLATE_INVALSET_P_DECL>
    491void InvalSet<TEMPLATE_INVALSET_P_DEF>::Clean() {
    492  VIXL_ASSERT(monitor() == 0);
    493  if (empty() || !IsUsingVector()) {
    494    return;
    495  }
    496  // Manually iterate through the vector storage to discard invalid elements.
    497  ElementType* start = &(vector_->front());
    498  ElementType* end = start + vector_->size();
    499  ElementType* c = start;
    500  ElementType* first_invalid;
    501  ElementType* first_valid;
    502  ElementType* next_invalid;
    503
    504  while (c < end && IsValid(*c)) { c++; }
    505  first_invalid = c;
    506
    507  while (c < end) {
    508    while (c < end && !IsValid(*c)) { c++; }
    509    first_valid = c;
    510    while (c < end && IsValid(*c)) { c++; }
    511    next_invalid = c;
    512
    513    ptrdiff_t n_moved_elements = (next_invalid - first_valid);
    514    memmove(first_invalid, first_valid,  n_moved_elements * sizeof(*c));
    515    first_invalid = first_invalid + n_moved_elements;
    516    c = next_invalid;
    517  }
    518
    519  // Delete the trailing invalid elements.
    520  vector_->erase(vector_->begin() + (first_invalid - start), vector_->end());
    521  VIXL_ASSERT(vector_->size() == size_);
    522
    523  if (sorted_) {
    524    valid_cached_min_ = true;
    525    cached_min_index_ = 0;
    526    cached_min_key_ = Key(*ElementAt(0));
    527  } else {
    528    valid_cached_min_ = false;
    529  }
    530}
    531
    532
    533template<TEMPLATE_INVALSET_P_DECL>
    534const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Front() const {
    535  VIXL_ASSERT(!empty());
    536  return IsUsingVector() ? vector_->front() : preallocated_[0];
    537}
    538
    539
    540template<TEMPLATE_INVALSET_P_DECL>
    541const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Back() const {
    542  VIXL_ASSERT(!empty());
    543  return IsUsingVector() ? vector_->back() : preallocated_[size_ - 1];
    544}
    545
    546
    547template<TEMPLATE_INVALSET_P_DECL>
    548const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::CleanBack() {
    549  VIXL_ASSERT(monitor() == 0);
    550  if (IsUsingVector()) {
    551    // Delete the invalid trailing elements.
    552    typename std::vector<ElementType>::reverse_iterator it = vector_->rbegin();
    553    while (!IsValid(*it)) {
    554      it++;
    555    }
    556    vector_->erase(it.base(), vector_->end());
    557  }
    558  return Back();
    559}
    560
    561
    562template<TEMPLATE_INVALSET_P_DECL>
    563const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() const {
    564  return IsUsingVector() ? &(vector_->front()) : preallocated_;
    565}
    566
    567
    568template<TEMPLATE_INVALSET_P_DECL>
    569const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() const {
    570  return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_;
    571}
    572
    573
    574template<TEMPLATE_INVALSET_P_DECL>
    575ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() {
    576  return IsUsingVector() ? &(vector_->front()) : preallocated_;
    577}
    578
    579
    580template<TEMPLATE_INVALSET_P_DECL>
    581ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() {
    582  return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_;
    583}
    584
    585
    586template<TEMPLATE_INVALSET_P_DECL>
    587size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::ElementIndex(
    588    const ElementType* element) const {
    589  VIXL_ASSERT((StorageBegin() <= element) && (element < StorageEnd()));
    590  return element - StorageBegin();
    591}
    592
    593
    594template<TEMPLATE_INVALSET_P_DECL>
    595const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::ElementAt(
    596    size_t index) const {
    597  VIXL_ASSERT(
    598      (IsUsingVector() && (index < vector_->size())) || (index < size_));
    599  return StorageBegin() + index;
    600}
    601
    602template<TEMPLATE_INVALSET_P_DECL>
    603ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::ElementAt(size_t index) {
    604  VIXL_ASSERT(
    605      (IsUsingVector() && (index < vector_->size())) || (index < size_));
    606  return StorageBegin() + index;
    607}
    608
    609template<TEMPLATE_INVALSET_P_DECL>
    610const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::FirstValidElement(
    611    const ElementType* from, const ElementType* end) {
    612  while ((from < end) && !IsValid(*from)) {
    613    from++;
    614  }
    615  return from;
    616}
    617
    618
    619template<TEMPLATE_INVALSET_P_DECL>
    620void InvalSet<TEMPLATE_INVALSET_P_DEF>::CacheMinElement() {
    621  VIXL_ASSERT(monitor() == 0);
    622  VIXL_ASSERT(!empty());
    623
    624  if (valid_cached_min_) {
    625    return;
    626  }
    627
    628  if (sorted_) {
    629    const ElementType* min = FirstValidElement(StorageBegin(), StorageEnd());
    630    cached_min_index_ = ElementIndex(min);
    631    cached_min_key_ = Key(*min);
    632    valid_cached_min_ = true;
    633  } else {
    634    Sort(kHardSort);
    635  }
    636  VIXL_ASSERT(valid_cached_min_);
    637}
    638
    639
    640template<TEMPLATE_INVALSET_P_DECL>
    641bool InvalSet<TEMPLATE_INVALSET_P_DEF>::ShouldReclaimMemory() const {
    642  if (!IsUsingVector()) {
    643    return false;
    644  }
    645  size_t n_invalid_elements = vector_->size() - size_;
    646  return (n_invalid_elements > RECLAIM_FROM) &&
    647         (n_invalid_elements > vector_->size() / RECLAIM_FACTOR);
    648}
    649
    650
    651template<TEMPLATE_INVALSET_P_DECL>
    652void InvalSet<TEMPLATE_INVALSET_P_DEF>::ReclaimMemory() {
    653  VIXL_ASSERT(monitor() == 0);
    654  Clean();
    655}
    656
    657
    658template<class S>
    659InvalSetIterator<S>::InvalSetIterator(S* inval_set)
    660    : using_vector_((inval_set != NULL) && inval_set->IsUsingVector()),
    661      index_(0),
    662      inval_set_(inval_set) {
    663  if (inval_set != NULL) {
    664    inval_set->Sort(S::kSoftSort);
    665#ifdef VIXL_DEBUG
    666    inval_set->Acquire();
    667#endif
    668    if (using_vector_) {
    669      iterator_ = typename std::vector<ElementType>::iterator(
    670          inval_set_->vector_->begin());
    671    }
    672    MoveToValidElement();
    673  }
    674}
    675
    676
    677template<class S>
    678InvalSetIterator<S>::~InvalSetIterator() {
    679#ifdef VIXL_DEBUG
    680  if (inval_set_ != NULL) {
    681    inval_set_->Release();
    682  }
    683#endif
    684}
    685
    686
    687template<class S>
    688typename S::_ElementType* InvalSetIterator<S>::Current() const {
    689  VIXL_ASSERT(!Done());
    690  if (using_vector_) {
    691    return &(*iterator_);
    692  } else {
    693    return &(inval_set_->preallocated_[index_]);
    694  }
    695}
    696
    697
    698template<class S>
    699void InvalSetIterator<S>::Advance() {
    700  VIXL_ASSERT(!Done());
    701  if (using_vector_) {
    702    iterator_++;
    703#ifdef VIXL_DEBUG
    704    index_++;
    705#endif
    706    MoveToValidElement();
    707  } else {
    708    index_++;
    709  }
    710}
    711
    712
    713template<class S>
    714bool InvalSetIterator<S>::Done() const {
    715  if (using_vector_) {
    716    bool done = (iterator_ == inval_set_->vector_->end());
    717    VIXL_ASSERT(done == (index_ == inval_set_->size()));
    718    return done;
    719  } else {
    720    return index_ == inval_set_->size();
    721  }
    722}
    723
    724
    725template<class S>
    726void InvalSetIterator<S>::Finish() {
    727  VIXL_ASSERT(inval_set_->sorted_);
    728  if (using_vector_) {
    729    iterator_ = inval_set_->vector_->end();
    730  }
    731  index_ = inval_set_->size();
    732}
    733
    734
    735template<class S>
    736void InvalSetIterator<S>::DeleteCurrentAndAdvance() {
    737  if (using_vector_) {
    738    inval_set_->EraseInternal(&(*iterator_));
    739    MoveToValidElement();
    740  } else {
    741    inval_set_->EraseInternal(inval_set_->preallocated_ + index_);
    742  }
    743}
    744
    745
    746template<class S>
    747bool InvalSetIterator<S>::IsValid(const ElementType& element) {
    748  return S::IsValid(element);
    749}
    750
    751
    752template<class S>
    753typename S::_KeyType InvalSetIterator<S>::Key(const ElementType& element) {
    754  return S::Key(element);
    755}
    756
    757
    758template<class S>
    759void InvalSetIterator<S>::MoveToValidElement() {
    760  if (using_vector_) {
    761    while ((iterator_ != inval_set_->vector_->end()) && !IsValid(*iterator_)) {
    762      iterator_++;
    763    }
    764  } else {
    765    VIXL_ASSERT(inval_set_->empty() || IsValid(inval_set_->preallocated_[0]));
    766    // Nothing to do.
    767  }
    768}
    769
    770#undef TEMPLATE_INVALSET_P_DECL
    771#undef TEMPLATE_INVALSET_P_DEF
    772
    773}  // namespace vixl
    774
    775#endif  // VIXL_INVALSET_H_