| // Copyright 2015, VIXL authors |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // * Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // * Neither the name of ARM Limited nor the names of its contributors may be |
| // used to endorse or promote products derived from this software without |
| // specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND |
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #ifndef VIXL_INVALSET_H_ |
| #define VIXL_INVALSET_H_ |
| |
| #include <cstring> |
| |
| #include <algorithm> |
| #include <vector> |
| |
| #include "globals-vixl.h" |
| |
| namespace vixl { |
| |
| // We define a custom data structure template and its iterator as `std` |
| // containers do not fit the performance requirements for some of our use cases. |
| // |
| // The structure behaves like an iterable unordered set with special properties |
| // and restrictions. "InvalSet" stands for "Invalidatable Set". |
| // |
| // Restrictions and requirements: |
| // - Adding an element already present in the set is illegal. In debug mode, |
| // this is checked at insertion time. |
| // - The templated class `ElementType` must provide comparison operators so that |
| // `std::sort()` can be used. |
| // - A key must be available to represent invalid elements. |
| // - Elements with an invalid key must compare higher or equal to any other |
| // element. |
| // |
| // Use cases and performance considerations: |
| // Our use cases present two specificities that allow us to design this |
| // structure to provide fast insertion *and* fast search and deletion |
| // operations: |
| // - Elements are (generally) inserted in order (sorted according to their key). |
| // - A key is available to mark elements as invalid (deleted). |
| // The backing `std::vector` allows for fast insertions. When |
| // searching for an element we ensure the elements are sorted (this is generally |
| // the case) and perform a binary search. When deleting an element we do not |
| // free the associated memory immediately. Instead, an element to be deleted is |
| // marked with the 'invalid' key. Other methods of the container take care of |
| // ignoring entries marked as invalid. |
| // To avoid the overhead of the `std::vector` container when only few entries |
| // are used, a number of elements are preallocated. |
| |
| // 'ElementType' and 'KeyType' are respectively the types of the elements and |
| // their key. The structure only reclaims memory when safe to do so, if the |
| // number of elements that can be reclaimed is greater than `RECLAIM_FROM` and |
| // greater than `<total number of elements> / RECLAIM_FACTOR. |
| // clang-format off |
| #define TEMPLATE_INVALSET_P_DECL \ |
| class ElementType, \ |
| unsigned N_PREALLOCATED_ELEMENTS, \ |
| class KeyType, \ |
| KeyType INVALID_KEY, \ |
| size_t RECLAIM_FROM, \ |
| unsigned RECLAIM_FACTOR |
| // clang-format on |
| |
| #define TEMPLATE_INVALSET_P_DEF \ |
| ElementType, N_PREALLOCATED_ELEMENTS, KeyType, INVALID_KEY, RECLAIM_FROM, \ |
| RECLAIM_FACTOR |
| |
| template <class S> |
| class InvalSetIterator; // Forward declaration. |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| class InvalSet { |
| public: |
| InvalSet(); |
| ~InvalSet(); |
| |
| static const size_t kNPreallocatedElements = N_PREALLOCATED_ELEMENTS; |
| static const KeyType kInvalidKey = INVALID_KEY; |
| |
| // C++ STL iterator interface. |
| typedef InvalSetIterator<InvalSet<TEMPLATE_INVALSET_P_DEF> > iterator; |
| iterator begin(); |
| iterator end(); |
| |
| // It is illegal to insert an element already present in the set. |
| void insert(const ElementType& element); |
| |
| // Looks for the specified element in the set and - if found - deletes it. |
| // The return value is the number of elements erased: either 0 or 1. |
| size_t erase(const ElementType& element); |
| |
| // This indicates the number of (valid) elements stored in this set. |
| size_t size() const; |
| |
| // Returns true if no elements are stored in the set. |
| // Note that this does not mean the the backing storage is empty: it can still |
| // contain invalid elements. |
| bool empty() const; |
| |
| void clear(); |
| |
| const ElementType GetMinElement(); |
| |
| // This returns the key of the minimum element in the set. |
| KeyType GetMinElementKey(); |
| |
| static bool IsValid(const ElementType& element); |
| static KeyType GetKey(const ElementType& element); |
| static void SetKey(ElementType* element, KeyType key); |
| |
| typedef ElementType _ElementType; |
| typedef KeyType _KeyType; |
| |
| protected: |
| // Returns a pointer to the element in vector_ if it was found, or NULL |
| // otherwise. |
| ElementType* Search(const ElementType& element); |
| |
| // The argument *must* point to an element stored in *this* set. |
| // This function is not allowed to move elements in the backing vector |
| // storage. |
| void EraseInternal(ElementType* element); |
| |
| // The elements in the range searched must be sorted. |
| ElementType* BinarySearch(const ElementType& element, |
| ElementType* start, |
| ElementType* end) const; |
| |
| // Sort the elements. |
| enum SortType { |
| // The 'hard' version guarantees that invalid elements are moved to the end |
| // of the container. |
| kHardSort, |
| // The 'soft' version only guarantees that the elements will be sorted. |
| // Invalid elements may still be present anywhere in the set. |
| kSoftSort |
| }; |
| void Sort(SortType sort_type); |
| |
| // Delete the elements that have an invalid key. The complexity is linear |
| // with the size of the vector. |
| void Clean(); |
| |
| const ElementType Front() const; |
| const ElementType Back() const; |
| |
| // Delete invalid trailing elements and return the last valid element in the |
| // set. |
| const ElementType CleanBack(); |
| |
| // Returns a pointer to the start or end of the backing storage. |
| const ElementType* StorageBegin() const; |
| const ElementType* StorageEnd() const; |
| ElementType* StorageBegin(); |
| ElementType* StorageEnd(); |
| |
| // Returns the index of the element within the backing storage. The element |
| // must belong to the backing storage. |
| size_t GetElementIndex(const ElementType* element) const; |
| |
| // Returns the element at the specified index in the backing storage. |
| const ElementType* GetElementAt(size_t index) const; |
| ElementType* GetElementAt(size_t index); |
| |
| static const ElementType* GetFirstValidElement(const ElementType* from, |
| const ElementType* end); |
| |
| void CacheMinElement(); |
| const ElementType GetCachedMinElement() const; |
| |
| bool ShouldReclaimMemory() const; |
| void ReclaimMemory(); |
| |
| bool IsUsingVector() const { return vector_ != NULL; } |
| void SetSorted(bool sorted) { sorted_ = sorted; } |
| |
| // We cache some data commonly required by users to improve performance. |
| // We cannot cache pointers to elements as we do not control the backing |
| // storage. |
| bool valid_cached_min_; |
| size_t cached_min_index_; // Valid iff `valid_cached_min_` is true. |
| KeyType cached_min_key_; // Valid iff `valid_cached_min_` is true. |
| |
| // Indicates whether the elements are sorted. |
| bool sorted_; |
| |
| // This represents the number of (valid) elements in this set. |
| size_t size_; |
| |
| // The backing storage is either the array of preallocated elements or the |
| // vector. The structure starts by using the preallocated elements, and |
| // transitions (permanently) to using the vector once more than |
| // kNPreallocatedElements are used. |
| // Elements are only invalidated when using the vector. The preallocated |
| // storage always only contains valid elements. |
| ElementType preallocated_[kNPreallocatedElements]; |
| std::vector<ElementType>* vector_; |
| |
| // Iterators acquire and release this monitor. While a set is acquired, |
| // certain operations are illegal to ensure that the iterator will |
| // correctly iterate over the elements in the set. |
| int monitor_; |
| #ifdef VIXL_DEBUG |
| int monitor() const { return monitor_; } |
| void Acquire() { monitor_++; } |
| void Release() { |
| monitor_--; |
| VIXL_ASSERT(monitor_ >= 0); |
| } |
| #endif |
| |
| private: |
| // The copy constructor and assignment operator are not used and the defaults |
| // are unsafe, so disable them (without an implementation). |
| #if __cplusplus >= 201103L |
| InvalSet(const InvalSet& other) = delete; |
| InvalSet operator=(const InvalSet& other) = delete; |
| #else |
| InvalSet(const InvalSet& other); |
| InvalSet operator=(const InvalSet& other); |
| #endif |
| |
| friend class InvalSetIterator<InvalSet<TEMPLATE_INVALSET_P_DEF> >; |
| }; |
| |
| |
| template <class S> |
| class InvalSetIterator : public std::iterator<std::forward_iterator_tag, |
| typename S::_ElementType> { |
| private: |
| // Redefine types to mirror the associated set types. |
| typedef typename S::_ElementType ElementType; |
| typedef typename S::_KeyType KeyType; |
| |
| public: |
| explicit InvalSetIterator(S* inval_set = NULL); |
| |
| // This class implements the standard copy-swap idiom. |
| ~InvalSetIterator(); |
| InvalSetIterator(const InvalSetIterator<S>& other); |
| InvalSetIterator<S>& operator=(InvalSetIterator<S> other); |
| #if __cplusplus >= 201103L |
| InvalSetIterator(InvalSetIterator<S>&& other) noexcept; |
| #endif |
| |
| friend void swap(InvalSetIterator<S>& a, InvalSetIterator<S>& b) { |
| using std::swap; |
| swap(a.using_vector_, b.using_vector_); |
| swap(a.index_, b.index_); |
| swap(a.inval_set_, b.inval_set_); |
| } |
| |
| // Return true if the iterator is at the end of the set. |
| bool Done() const; |
| |
| // Move this iterator to the end of the set. |
| void Finish(); |
| |
| // Delete the current element and advance the iterator to point to the next |
| // element. |
| void DeleteCurrentAndAdvance(); |
| |
| static bool IsValid(const ElementType& element); |
| static KeyType GetKey(const ElementType& element); |
| |
| // Extra helpers to support the forward-iterator interface. |
| InvalSetIterator<S>& operator++(); // Pre-increment. |
| InvalSetIterator<S> operator++(int); // Post-increment. |
| bool operator==(const InvalSetIterator<S>& rhs) const; |
| bool operator!=(const InvalSetIterator<S>& rhs) const { |
| return !(*this == rhs); |
| } |
| ElementType& operator*() { return *Current(); } |
| const ElementType& operator*() const { return *Current(); } |
| ElementType* operator->() { return Current(); } |
| const ElementType* operator->() const { return Current(); } |
| |
| protected: |
| void MoveToValidElement(); |
| |
| // Indicates if the iterator is looking at the vector or at the preallocated |
| // elements. |
| bool using_vector_; |
| // Used when looking at the preallocated elements, or in debug mode when using |
| // the vector to track how many times the iterator has advanced. |
| size_t index_; |
| typename std::vector<ElementType>::iterator iterator_; |
| S* inval_set_; |
| |
| // TODO: These helpers are deprecated and will be removed in future versions |
| // of VIXL. |
| ElementType* Current() const; |
| void Advance(); |
| }; |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| InvalSet<TEMPLATE_INVALSET_P_DEF>::InvalSet() |
| : valid_cached_min_(false), sorted_(true), size_(0), vector_(NULL) { |
| #ifdef VIXL_DEBUG |
| monitor_ = 0; |
| #endif |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| InvalSet<TEMPLATE_INVALSET_P_DEF>::~InvalSet() { |
| VIXL_ASSERT(monitor_ == 0); |
| delete vector_; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| typename InvalSet<TEMPLATE_INVALSET_P_DEF>::iterator |
| InvalSet<TEMPLATE_INVALSET_P_DEF>::begin() { |
| return iterator(this); |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| typename InvalSet<TEMPLATE_INVALSET_P_DEF>::iterator |
| InvalSet<TEMPLATE_INVALSET_P_DEF>::end() { |
| iterator end(this); |
| end.Finish(); |
| return end; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::insert(const ElementType& element) { |
| VIXL_ASSERT(monitor() == 0); |
| VIXL_ASSERT(IsValid(element)); |
| VIXL_ASSERT(Search(element) == NULL); |
| SetSorted(empty() || (sorted_ && (element > CleanBack()))); |
| if (IsUsingVector()) { |
| vector_->push_back(element); |
| } else { |
| if (size_ < kNPreallocatedElements) { |
| preallocated_[size_] = element; |
| } else { |
| // Transition to using the vector. |
| vector_ = |
| new std::vector<ElementType>(preallocated_, preallocated_ + size_); |
| vector_->push_back(element); |
| } |
| } |
| size_++; |
| |
| if (valid_cached_min_ && (element < GetMinElement())) { |
| cached_min_index_ = IsUsingVector() ? vector_->size() - 1 : size_ - 1; |
| cached_min_key_ = GetKey(element); |
| valid_cached_min_ = true; |
| } |
| |
| if (ShouldReclaimMemory()) { |
| ReclaimMemory(); |
| } |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::erase(const ElementType& element) { |
| VIXL_ASSERT(monitor() == 0); |
| VIXL_ASSERT(IsValid(element)); |
| ElementType* local_element = Search(element); |
| if (local_element != NULL) { |
| EraseInternal(local_element); |
| return 1; |
| } |
| return 0; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::Search( |
| const ElementType& element) { |
| VIXL_ASSERT(monitor() == 0); |
| if (empty()) { |
| return NULL; |
| } |
| if (ShouldReclaimMemory()) { |
| ReclaimMemory(); |
| } |
| if (!sorted_) { |
| Sort(kHardSort); |
| } |
| if (!valid_cached_min_) { |
| CacheMinElement(); |
| } |
| return BinarySearch(element, GetElementAt(cached_min_index_), StorageEnd()); |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::size() const { |
| return size_; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| bool InvalSet<TEMPLATE_INVALSET_P_DEF>::empty() const { |
| return size_ == 0; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::clear() { |
| VIXL_ASSERT(monitor() == 0); |
| size_ = 0; |
| if (IsUsingVector()) { |
| vector_->clear(); |
| } |
| SetSorted(true); |
| valid_cached_min_ = false; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::GetMinElement() { |
| VIXL_ASSERT(monitor() == 0); |
| VIXL_ASSERT(!empty()); |
| CacheMinElement(); |
| return *GetElementAt(cached_min_index_); |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| KeyType InvalSet<TEMPLATE_INVALSET_P_DEF>::GetMinElementKey() { |
| VIXL_ASSERT(monitor() == 0); |
| if (valid_cached_min_) { |
| return cached_min_key_; |
| } else { |
| return GetKey(GetMinElement()); |
| } |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| bool InvalSet<TEMPLATE_INVALSET_P_DEF>::IsValid(const ElementType& element) { |
| return GetKey(element) != kInvalidKey; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::EraseInternal(ElementType* element) { |
| // Note that this function must be safe even while an iterator has acquired |
| // this set. |
| VIXL_ASSERT(element != NULL); |
| size_t deleted_index = GetElementIndex(element); |
| if (IsUsingVector()) { |
| VIXL_ASSERT((&(vector_->front()) <= element) && |
| (element <= &(vector_->back()))); |
| SetKey(element, kInvalidKey); |
| } else { |
| VIXL_ASSERT((preallocated_ <= element) && |
| (element < (preallocated_ + kNPreallocatedElements))); |
| ElementType* end = preallocated_ + kNPreallocatedElements; |
| size_t copy_size = sizeof(*element) * (end - element - 1); |
| memmove(element, element + 1, copy_size); |
| } |
| size_--; |
| |
| if (valid_cached_min_ && (deleted_index == cached_min_index_)) { |
| if (sorted_ && !empty()) { |
| const ElementType* min = GetFirstValidElement(element, StorageEnd()); |
| cached_min_index_ = GetElementIndex(min); |
| cached_min_key_ = GetKey(*min); |
| valid_cached_min_ = true; |
| } else { |
| valid_cached_min_ = false; |
| } |
| } |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::BinarySearch( |
| const ElementType& element, ElementType* start, ElementType* end) const { |
| if (start == end) { |
| return NULL; |
| } |
| VIXL_ASSERT(sorted_); |
| VIXL_ASSERT(start < end); |
| VIXL_ASSERT(!empty()); |
| |
| // Perform a binary search through the elements while ignoring invalid |
| // elements. |
| ElementType* elements = start; |
| size_t low = 0; |
| size_t high = (end - start) - 1; |
| while (low < high) { |
| // Find valid bounds. |
| while (!IsValid(elements[low]) && (low < high)) ++low; |
| while (!IsValid(elements[high]) && (low < high)) --high; |
| VIXL_ASSERT(low <= high); |
| // Avoid overflow when computing the middle index. |
| size_t middle = low + (high - low) / 2; |
| if ((middle == low) || (middle == high)) { |
| break; |
| } |
| while ((middle < high - 1) && !IsValid(elements[middle])) ++middle; |
| while ((low + 1 < middle) && !IsValid(elements[middle])) --middle; |
| if (!IsValid(elements[middle])) { |
| break; |
| } |
| if (elements[middle] < element) { |
| low = middle; |
| } else { |
| high = middle; |
| } |
| } |
| |
| if (elements[low] == element) return &elements[low]; |
| if (elements[high] == element) return &elements[high]; |
| return NULL; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::Sort(SortType sort_type) { |
| if (sort_type == kSoftSort) { |
| if (sorted_) { |
| return; |
| } |
| } |
| VIXL_ASSERT(monitor() == 0); |
| if (empty()) { |
| return; |
| } |
| |
| Clean(); |
| std::sort(StorageBegin(), StorageEnd()); |
| |
| SetSorted(true); |
| cached_min_index_ = 0; |
| cached_min_key_ = GetKey(Front()); |
| valid_cached_min_ = true; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::Clean() { |
| VIXL_ASSERT(monitor() == 0); |
| if (empty() || !IsUsingVector()) { |
| return; |
| } |
| // Manually iterate through the vector storage to discard invalid elements. |
| ElementType* start = &(vector_->front()); |
| ElementType* end = start + vector_->size(); |
| ElementType* c = start; |
| ElementType* first_invalid; |
| ElementType* first_valid; |
| ElementType* next_invalid; |
| |
| while ((c < end) && IsValid(*c)) c++; |
| first_invalid = c; |
| |
| while (c < end) { |
| while ((c < end) && !IsValid(*c)) c++; |
| first_valid = c; |
| while ((c < end) && IsValid(*c)) c++; |
| next_invalid = c; |
| |
| ptrdiff_t n_moved_elements = (next_invalid - first_valid); |
| memmove(first_invalid, first_valid, n_moved_elements * sizeof(*c)); |
| first_invalid = first_invalid + n_moved_elements; |
| c = next_invalid; |
| } |
| |
| // Delete the trailing invalid elements. |
| vector_->erase(vector_->begin() + (first_invalid - start), vector_->end()); |
| VIXL_ASSERT(vector_->size() == size_); |
| |
| if (sorted_) { |
| valid_cached_min_ = true; |
| cached_min_index_ = 0; |
| cached_min_key_ = GetKey(*GetElementAt(0)); |
| } else { |
| valid_cached_min_ = false; |
| } |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Front() const { |
| VIXL_ASSERT(!empty()); |
| return IsUsingVector() ? vector_->front() : preallocated_[0]; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Back() const { |
| VIXL_ASSERT(!empty()); |
| return IsUsingVector() ? vector_->back() : preallocated_[size_ - 1]; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::CleanBack() { |
| VIXL_ASSERT(monitor() == 0); |
| if (IsUsingVector()) { |
| // Delete the invalid trailing elements. |
| typename std::vector<ElementType>::reverse_iterator it = vector_->rbegin(); |
| while (!IsValid(*it)) { |
| it++; |
| } |
| vector_->erase(it.base(), vector_->end()); |
| } |
| return Back(); |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() const { |
| return IsUsingVector() ? &(vector_->front()) : preallocated_; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() const { |
| return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() { |
| return IsUsingVector() ? &(vector_->front()) : preallocated_; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() { |
| return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::GetElementIndex( |
| const ElementType* element) const { |
| VIXL_ASSERT((StorageBegin() <= element) && (element < StorageEnd())); |
| return element - StorageBegin(); |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::GetElementAt( |
| size_t index) const { |
| VIXL_ASSERT((IsUsingVector() && (index < vector_->size())) || |
| (index < size_)); |
| return StorageBegin() + index; |
| } |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::GetElementAt(size_t index) { |
| VIXL_ASSERT((IsUsingVector() && (index < vector_->size())) || |
| (index < size_)); |
| return StorageBegin() + index; |
| } |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::GetFirstValidElement( |
| const ElementType* from, const ElementType* end) { |
| while ((from < end) && !IsValid(*from)) { |
| from++; |
| } |
| return from; |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::CacheMinElement() { |
| VIXL_ASSERT(monitor() == 0); |
| VIXL_ASSERT(!empty()); |
| |
| if (valid_cached_min_) { |
| return; |
| } |
| |
| if (sorted_) { |
| const ElementType* min = GetFirstValidElement(StorageBegin(), StorageEnd()); |
| cached_min_index_ = GetElementIndex(min); |
| cached_min_key_ = GetKey(*min); |
| valid_cached_min_ = true; |
| } else { |
| Sort(kHardSort); |
| } |
| VIXL_ASSERT(valid_cached_min_); |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| bool InvalSet<TEMPLATE_INVALSET_P_DEF>::ShouldReclaimMemory() const { |
| if (!IsUsingVector()) { |
| return false; |
| } |
| size_t n_invalid_elements = vector_->size() - size_; |
| return (n_invalid_elements > RECLAIM_FROM) && |
| (n_invalid_elements > vector_->size() / RECLAIM_FACTOR); |
| } |
| |
| |
| template <TEMPLATE_INVALSET_P_DECL> |
| void InvalSet<TEMPLATE_INVALSET_P_DEF>::ReclaimMemory() { |
| VIXL_ASSERT(monitor() == 0); |
| Clean(); |
| } |
| |
| |
| template <class S> |
| InvalSetIterator<S>::InvalSetIterator(S* inval_set) |
| : using_vector_((inval_set != NULL) && inval_set->IsUsingVector()), |
| index_(0), |
| inval_set_(inval_set) { |
| if (inval_set != NULL) { |
| inval_set->Sort(S::kSoftSort); |
| #ifdef VIXL_DEBUG |
| inval_set->Acquire(); |
| #endif |
| if (using_vector_) { |
| iterator_ = typename std::vector<ElementType>::iterator( |
| inval_set_->vector_->begin()); |
| } |
| MoveToValidElement(); |
| } |
| } |
| |
| |
| template <class S> |
| InvalSetIterator<S>::~InvalSetIterator() { |
| #ifdef VIXL_DEBUG |
| if (inval_set_ != NULL) inval_set_->Release(); |
| #endif |
| } |
| |
| |
| template <class S> |
| typename S::_ElementType* InvalSetIterator<S>::Current() const { |
| VIXL_ASSERT(!Done()); |
| if (using_vector_) { |
| return &(*iterator_); |
| } else { |
| return &(inval_set_->preallocated_[index_]); |
| } |
| } |
| |
| |
| template <class S> |
| void InvalSetIterator<S>::Advance() { |
| ++(*this); |
| } |
| |
| |
| template <class S> |
| bool InvalSetIterator<S>::Done() const { |
| if (using_vector_) { |
| bool done = (iterator_ == inval_set_->vector_->end()); |
| VIXL_ASSERT(done == (index_ == inval_set_->size())); |
| return done; |
| } else { |
| return index_ == inval_set_->size(); |
| } |
| } |
| |
| |
| template <class S> |
| void InvalSetIterator<S>::Finish() { |
| VIXL_ASSERT(inval_set_->sorted_); |
| if (using_vector_) { |
| iterator_ = inval_set_->vector_->end(); |
| } |
| index_ = inval_set_->size(); |
| } |
| |
| |
| template <class S> |
| void InvalSetIterator<S>::DeleteCurrentAndAdvance() { |
| if (using_vector_) { |
| inval_set_->EraseInternal(&(*iterator_)); |
| MoveToValidElement(); |
| } else { |
| inval_set_->EraseInternal(inval_set_->preallocated_ + index_); |
| } |
| } |
| |
| |
| template <class S> |
| bool InvalSetIterator<S>::IsValid(const ElementType& element) { |
| return S::IsValid(element); |
| } |
| |
| |
| template <class S> |
| typename S::_KeyType InvalSetIterator<S>::GetKey(const ElementType& element) { |
| return S::GetKey(element); |
| } |
| |
| |
| template <class S> |
| void InvalSetIterator<S>::MoveToValidElement() { |
| if (using_vector_) { |
| while ((iterator_ != inval_set_->vector_->end()) && !IsValid(*iterator_)) { |
| iterator_++; |
| } |
| } else { |
| VIXL_ASSERT(inval_set_->empty() || IsValid(inval_set_->preallocated_[0])); |
| // Nothing to do. |
| } |
| } |
| |
| |
| template <class S> |
| InvalSetIterator<S>::InvalSetIterator(const InvalSetIterator<S>& other) |
| : using_vector_(other.using_vector_), |
| index_(other.index_), |
| inval_set_(other.inval_set_) { |
| #ifdef VIXL_DEBUG |
| if (inval_set_ != NULL) inval_set_->Acquire(); |
| #endif |
| } |
| |
| |
| #if __cplusplus >= 201103L |
| template <class S> |
| InvalSetIterator<S>::InvalSetIterator(InvalSetIterator<S>&& other) noexcept |
| : using_vector_(false), |
| index_(0), |
| inval_set_(NULL) { |
| swap(*this, other); |
| } |
| #endif |
| |
| |
| template <class S> |
| InvalSetIterator<S>& InvalSetIterator<S>::operator=(InvalSetIterator<S> other) { |
| swap(*this, other); |
| return *this; |
| } |
| |
| |
| template <class S> |
| bool InvalSetIterator<S>::operator==(const InvalSetIterator<S>& rhs) const { |
| bool equal = (inval_set_ == rhs.inval_set_); |
| |
| // If the inval_set_ matches, using_vector_ must also match. |
| VIXL_ASSERT(!equal || (using_vector_ == rhs.using_vector_)); |
| |
| if (using_vector_) { |
| equal = equal && (iterator_ == rhs.iterator_); |
| // In debug mode, index_ is maintained even with using_vector_. |
| VIXL_ASSERT(!equal || (index_ == rhs.index_)); |
| } else { |
| equal = equal && (index_ == rhs.index_); |
| #ifdef DEBUG |
| // If not using_vector_, iterator_ should be default-initialised. |
| typename std::vector<ElementType>::iterator default_iterator; |
| VIXL_ASSERT(iterator_ == default_iterator); |
| VIXL_ASSERT(rhs.iterator_ == default_iterator); |
| #endif |
| } |
| return equal; |
| } |
| |
| |
| template <class S> |
| InvalSetIterator<S>& InvalSetIterator<S>::operator++() { |
| // Pre-increment. |
| VIXL_ASSERT(!Done()); |
| if (using_vector_) { |
| iterator_++; |
| #ifdef VIXL_DEBUG |
| index_++; |
| #endif |
| MoveToValidElement(); |
| } else { |
| index_++; |
| } |
| return *this; |
| } |
| |
| |
| template <class S> |
| InvalSetIterator<S> InvalSetIterator<S>::operator++(int /* unused */) { |
| // Post-increment. |
| VIXL_ASSERT(!Done()); |
| InvalSetIterator<S> old(*this); |
| ++(*this); |
| return old; |
| } |
| |
| |
| #undef TEMPLATE_INVALSET_P_DECL |
| #undef TEMPLATE_INVALSET_P_DEF |
| |
| } // namespace vixl |
| |
| #endif // VIXL_INVALSET_H_ |