1*f5c631daSSadaf Ebrahimi // Copyright 2015, VIXL authors
2*f5c631daSSadaf Ebrahimi // All rights reserved.
3*f5c631daSSadaf Ebrahimi //
4*f5c631daSSadaf Ebrahimi // Redistribution and use in source and binary forms, with or without
5*f5c631daSSadaf Ebrahimi // modification, are permitted provided that the following conditions are met:
6*f5c631daSSadaf Ebrahimi //
7*f5c631daSSadaf Ebrahimi // * Redistributions of source code must retain the above copyright notice,
8*f5c631daSSadaf Ebrahimi // this list of conditions and the following disclaimer.
9*f5c631daSSadaf Ebrahimi // * Redistributions in binary form must reproduce the above copyright notice,
10*f5c631daSSadaf Ebrahimi // this list of conditions and the following disclaimer in the documentation
11*f5c631daSSadaf Ebrahimi // and/or other materials provided with the distribution.
12*f5c631daSSadaf Ebrahimi // * Neither the name of ARM Limited nor the names of its contributors may be
13*f5c631daSSadaf Ebrahimi // used to endorse or promote products derived from this software without
14*f5c631daSSadaf Ebrahimi // specific prior written permission.
15*f5c631daSSadaf Ebrahimi //
16*f5c631daSSadaf Ebrahimi // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17*f5c631daSSadaf Ebrahimi // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18*f5c631daSSadaf Ebrahimi // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19*f5c631daSSadaf Ebrahimi // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20*f5c631daSSadaf Ebrahimi // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*f5c631daSSadaf Ebrahimi // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22*f5c631daSSadaf Ebrahimi // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23*f5c631daSSadaf Ebrahimi // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*f5c631daSSadaf Ebrahimi // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25*f5c631daSSadaf Ebrahimi // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*f5c631daSSadaf Ebrahimi
27*f5c631daSSadaf Ebrahimi #ifndef VIXL_INVALSET_H_
28*f5c631daSSadaf Ebrahimi #define VIXL_INVALSET_H_
29*f5c631daSSadaf Ebrahimi
30*f5c631daSSadaf Ebrahimi #include <cstring>
31*f5c631daSSadaf Ebrahimi
32*f5c631daSSadaf Ebrahimi #include <algorithm>
33*f5c631daSSadaf Ebrahimi #include <vector>
34*f5c631daSSadaf Ebrahimi
35*f5c631daSSadaf Ebrahimi #include "globals-vixl.h"
36*f5c631daSSadaf Ebrahimi
37*f5c631daSSadaf Ebrahimi namespace vixl {
38*f5c631daSSadaf Ebrahimi
39*f5c631daSSadaf Ebrahimi // We define a custom data structure template and its iterator as `std`
40*f5c631daSSadaf Ebrahimi // containers do not fit the performance requirements for some of our use cases.
41*f5c631daSSadaf Ebrahimi //
42*f5c631daSSadaf Ebrahimi // The structure behaves like an iterable unordered set with special properties
43*f5c631daSSadaf Ebrahimi // and restrictions. "InvalSet" stands for "Invalidatable Set".
44*f5c631daSSadaf Ebrahimi //
45*f5c631daSSadaf Ebrahimi // Restrictions and requirements:
46*f5c631daSSadaf Ebrahimi // - Adding an element already present in the set is illegal. In debug mode,
47*f5c631daSSadaf Ebrahimi // this is checked at insertion time.
48*f5c631daSSadaf Ebrahimi // - The templated class `ElementType` must provide comparison operators so that
49*f5c631daSSadaf Ebrahimi // `std::sort()` can be used.
50*f5c631daSSadaf Ebrahimi // - A key must be available to represent invalid elements.
51*f5c631daSSadaf Ebrahimi // - Elements with an invalid key must compare higher or equal to any other
52*f5c631daSSadaf Ebrahimi // element.
53*f5c631daSSadaf Ebrahimi //
54*f5c631daSSadaf Ebrahimi // Use cases and performance considerations:
55*f5c631daSSadaf Ebrahimi // Our use cases present two specificities that allow us to design this
56*f5c631daSSadaf Ebrahimi // structure to provide fast insertion *and* fast search and deletion
57*f5c631daSSadaf Ebrahimi // operations:
58*f5c631daSSadaf Ebrahimi // - Elements are (generally) inserted in order (sorted according to their key).
59*f5c631daSSadaf Ebrahimi // - A key is available to mark elements as invalid (deleted).
60*f5c631daSSadaf Ebrahimi // The backing `std::vector` allows for fast insertions. When
61*f5c631daSSadaf Ebrahimi // searching for an element we ensure the elements are sorted (this is generally
62*f5c631daSSadaf Ebrahimi // the case) and perform a binary search. When deleting an element we do not
63*f5c631daSSadaf Ebrahimi // free the associated memory immediately. Instead, an element to be deleted is
64*f5c631daSSadaf Ebrahimi // marked with the 'invalid' key. Other methods of the container take care of
65*f5c631daSSadaf Ebrahimi // ignoring entries marked as invalid.
66*f5c631daSSadaf Ebrahimi // To avoid the overhead of the `std::vector` container when only few entries
67*f5c631daSSadaf Ebrahimi // are used, a number of elements are preallocated.
68*f5c631daSSadaf Ebrahimi
69*f5c631daSSadaf Ebrahimi // 'ElementType' and 'KeyType' are respectively the types of the elements and
70*f5c631daSSadaf Ebrahimi // their key. The structure only reclaims memory when safe to do so, if the
71*f5c631daSSadaf Ebrahimi // number of elements that can be reclaimed is greater than `RECLAIM_FROM` and
72*f5c631daSSadaf Ebrahimi // greater than `<total number of elements> / RECLAIM_FACTOR.
73*f5c631daSSadaf Ebrahimi // clang-format off
74*f5c631daSSadaf Ebrahimi #define TEMPLATE_INVALSET_P_DECL \
75*f5c631daSSadaf Ebrahimi class ElementType, \
76*f5c631daSSadaf Ebrahimi unsigned N_PREALLOCATED_ELEMENTS, \
77*f5c631daSSadaf Ebrahimi class KeyType, \
78*f5c631daSSadaf Ebrahimi KeyType INVALID_KEY, \
79*f5c631daSSadaf Ebrahimi size_t RECLAIM_FROM, \
80*f5c631daSSadaf Ebrahimi unsigned RECLAIM_FACTOR
81*f5c631daSSadaf Ebrahimi // clang-format on
82*f5c631daSSadaf Ebrahimi
83*f5c631daSSadaf Ebrahimi #define TEMPLATE_INVALSET_P_DEF \
84*f5c631daSSadaf Ebrahimi ElementType, N_PREALLOCATED_ELEMENTS, KeyType, INVALID_KEY, RECLAIM_FROM, \
85*f5c631daSSadaf Ebrahimi RECLAIM_FACTOR
86*f5c631daSSadaf Ebrahimi
87*f5c631daSSadaf Ebrahimi template <class S>
88*f5c631daSSadaf Ebrahimi class InvalSetIterator; // Forward declaration.
89*f5c631daSSadaf Ebrahimi
90*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
91*f5c631daSSadaf Ebrahimi class InvalSet {
92*f5c631daSSadaf Ebrahimi public:
93*f5c631daSSadaf Ebrahimi InvalSet();
94*f5c631daSSadaf Ebrahimi ~InvalSet() VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION;
95*f5c631daSSadaf Ebrahimi
96*f5c631daSSadaf Ebrahimi static const size_t kNPreallocatedElements = N_PREALLOCATED_ELEMENTS;
97*f5c631daSSadaf Ebrahimi static const KeyType kInvalidKey = INVALID_KEY;
98*f5c631daSSadaf Ebrahimi
99*f5c631daSSadaf Ebrahimi // C++ STL iterator interface.
100*f5c631daSSadaf Ebrahimi typedef InvalSetIterator<InvalSet<TEMPLATE_INVALSET_P_DEF> > iterator;
101*f5c631daSSadaf Ebrahimi iterator begin();
102*f5c631daSSadaf Ebrahimi iterator end();
103*f5c631daSSadaf Ebrahimi
104*f5c631daSSadaf Ebrahimi // It is illegal to insert an element already present in the set.
105*f5c631daSSadaf Ebrahimi void insert(const ElementType& element);
106*f5c631daSSadaf Ebrahimi
107*f5c631daSSadaf Ebrahimi // Looks for the specified element in the set and - if found - deletes it.
108*f5c631daSSadaf Ebrahimi // The return value is the number of elements erased: either 0 or 1.
109*f5c631daSSadaf Ebrahimi size_t erase(const ElementType& element);
110*f5c631daSSadaf Ebrahimi
111*f5c631daSSadaf Ebrahimi // This indicates the number of (valid) elements stored in this set.
112*f5c631daSSadaf Ebrahimi size_t size() const;
113*f5c631daSSadaf Ebrahimi
114*f5c631daSSadaf Ebrahimi // Returns true if no elements are stored in the set.
115*f5c631daSSadaf Ebrahimi // Note that this does not mean the the backing storage is empty: it can still
116*f5c631daSSadaf Ebrahimi // contain invalid elements.
117*f5c631daSSadaf Ebrahimi bool empty() const;
118*f5c631daSSadaf Ebrahimi
119*f5c631daSSadaf Ebrahimi void clear();
120*f5c631daSSadaf Ebrahimi
121*f5c631daSSadaf Ebrahimi const ElementType GetMinElement();
122*f5c631daSSadaf Ebrahimi
123*f5c631daSSadaf Ebrahimi // This returns the key of the minimum element in the set.
124*f5c631daSSadaf Ebrahimi KeyType GetMinElementKey();
125*f5c631daSSadaf Ebrahimi
126*f5c631daSSadaf Ebrahimi static bool IsValid(const ElementType& element);
127*f5c631daSSadaf Ebrahimi static KeyType GetKey(const ElementType& element);
128*f5c631daSSadaf Ebrahimi static void SetKey(ElementType* element, KeyType key);
129*f5c631daSSadaf Ebrahimi
130*f5c631daSSadaf Ebrahimi typedef ElementType _ElementType;
131*f5c631daSSadaf Ebrahimi typedef KeyType _KeyType;
132*f5c631daSSadaf Ebrahimi
133*f5c631daSSadaf Ebrahimi protected:
134*f5c631daSSadaf Ebrahimi // Returns a pointer to the element in vector_ if it was found, or NULL
135*f5c631daSSadaf Ebrahimi // otherwise.
136*f5c631daSSadaf Ebrahimi ElementType* Search(const ElementType& element);
137*f5c631daSSadaf Ebrahimi
138*f5c631daSSadaf Ebrahimi // The argument *must* point to an element stored in *this* set.
139*f5c631daSSadaf Ebrahimi // This function is not allowed to move elements in the backing vector
140*f5c631daSSadaf Ebrahimi // storage.
141*f5c631daSSadaf Ebrahimi void EraseInternal(ElementType* element);
142*f5c631daSSadaf Ebrahimi
143*f5c631daSSadaf Ebrahimi // The elements in the range searched must be sorted.
144*f5c631daSSadaf Ebrahimi ElementType* BinarySearch(const ElementType& element,
145*f5c631daSSadaf Ebrahimi ElementType* start,
146*f5c631daSSadaf Ebrahimi ElementType* end) const;
147*f5c631daSSadaf Ebrahimi
148*f5c631daSSadaf Ebrahimi // Sort the elements.
149*f5c631daSSadaf Ebrahimi enum SortType {
150*f5c631daSSadaf Ebrahimi // The 'hard' version guarantees that invalid elements are moved to the end
151*f5c631daSSadaf Ebrahimi // of the container.
152*f5c631daSSadaf Ebrahimi kHardSort,
153*f5c631daSSadaf Ebrahimi // The 'soft' version only guarantees that the elements will be sorted.
154*f5c631daSSadaf Ebrahimi // Invalid elements may still be present anywhere in the set.
155*f5c631daSSadaf Ebrahimi kSoftSort
156*f5c631daSSadaf Ebrahimi };
157*f5c631daSSadaf Ebrahimi void Sort(SortType sort_type);
158*f5c631daSSadaf Ebrahimi
159*f5c631daSSadaf Ebrahimi // Delete the elements that have an invalid key. The complexity is linear
160*f5c631daSSadaf Ebrahimi // with the size of the vector.
161*f5c631daSSadaf Ebrahimi void Clean();
162*f5c631daSSadaf Ebrahimi
163*f5c631daSSadaf Ebrahimi const ElementType Front() const;
164*f5c631daSSadaf Ebrahimi const ElementType Back() const;
165*f5c631daSSadaf Ebrahimi
166*f5c631daSSadaf Ebrahimi // Delete invalid trailing elements and return the last valid element in the
167*f5c631daSSadaf Ebrahimi // set.
168*f5c631daSSadaf Ebrahimi const ElementType CleanBack();
169*f5c631daSSadaf Ebrahimi
170*f5c631daSSadaf Ebrahimi // Returns a pointer to the start or end of the backing storage.
171*f5c631daSSadaf Ebrahimi const ElementType* StorageBegin() const;
172*f5c631daSSadaf Ebrahimi const ElementType* StorageEnd() const;
173*f5c631daSSadaf Ebrahimi ElementType* StorageBegin();
174*f5c631daSSadaf Ebrahimi ElementType* StorageEnd();
175*f5c631daSSadaf Ebrahimi
176*f5c631daSSadaf Ebrahimi // Returns the index of the element within the backing storage. The element
177*f5c631daSSadaf Ebrahimi // must belong to the backing storage.
178*f5c631daSSadaf Ebrahimi size_t GetElementIndex(const ElementType* element) const;
179*f5c631daSSadaf Ebrahimi
180*f5c631daSSadaf Ebrahimi // Returns the element at the specified index in the backing storage.
181*f5c631daSSadaf Ebrahimi const ElementType* GetElementAt(size_t index) const;
182*f5c631daSSadaf Ebrahimi ElementType* GetElementAt(size_t index);
183*f5c631daSSadaf Ebrahimi
184*f5c631daSSadaf Ebrahimi static const ElementType* GetFirstValidElement(const ElementType* from,
185*f5c631daSSadaf Ebrahimi const ElementType* end);
186*f5c631daSSadaf Ebrahimi
187*f5c631daSSadaf Ebrahimi void CacheMinElement();
188*f5c631daSSadaf Ebrahimi const ElementType GetCachedMinElement() const;
189*f5c631daSSadaf Ebrahimi
190*f5c631daSSadaf Ebrahimi bool ShouldReclaimMemory() const;
191*f5c631daSSadaf Ebrahimi void ReclaimMemory();
192*f5c631daSSadaf Ebrahimi
IsUsingVector()193*f5c631daSSadaf Ebrahimi bool IsUsingVector() const { return vector_ != NULL; }
SetSorted(bool sorted)194*f5c631daSSadaf Ebrahimi void SetSorted(bool sorted) { sorted_ = sorted; }
195*f5c631daSSadaf Ebrahimi
196*f5c631daSSadaf Ebrahimi // We cache some data commonly required by users to improve performance.
197*f5c631daSSadaf Ebrahimi // We cannot cache pointers to elements as we do not control the backing
198*f5c631daSSadaf Ebrahimi // storage.
199*f5c631daSSadaf Ebrahimi bool valid_cached_min_;
200*f5c631daSSadaf Ebrahimi size_t cached_min_index_; // Valid iff `valid_cached_min_` is true.
201*f5c631daSSadaf Ebrahimi KeyType cached_min_key_; // Valid iff `valid_cached_min_` is true.
202*f5c631daSSadaf Ebrahimi
203*f5c631daSSadaf Ebrahimi // Indicates whether the elements are sorted.
204*f5c631daSSadaf Ebrahimi bool sorted_;
205*f5c631daSSadaf Ebrahimi
206*f5c631daSSadaf Ebrahimi // This represents the number of (valid) elements in this set.
207*f5c631daSSadaf Ebrahimi size_t size_;
208*f5c631daSSadaf Ebrahimi
209*f5c631daSSadaf Ebrahimi // The backing storage is either the array of preallocated elements or the
210*f5c631daSSadaf Ebrahimi // vector. The structure starts by using the preallocated elements, and
211*f5c631daSSadaf Ebrahimi // transitions (permanently) to using the vector once more than
212*f5c631daSSadaf Ebrahimi // kNPreallocatedElements are used.
213*f5c631daSSadaf Ebrahimi // Elements are only invalidated when using the vector. The preallocated
214*f5c631daSSadaf Ebrahimi // storage always only contains valid elements.
215*f5c631daSSadaf Ebrahimi ElementType preallocated_[kNPreallocatedElements];
216*f5c631daSSadaf Ebrahimi std::vector<ElementType>* vector_;
217*f5c631daSSadaf Ebrahimi
218*f5c631daSSadaf Ebrahimi // Iterators acquire and release this monitor. While a set is acquired,
219*f5c631daSSadaf Ebrahimi // certain operations are illegal to ensure that the iterator will
220*f5c631daSSadaf Ebrahimi // correctly iterate over the elements in the set.
221*f5c631daSSadaf Ebrahimi int monitor_;
222*f5c631daSSadaf Ebrahimi #ifdef VIXL_DEBUG
monitor()223*f5c631daSSadaf Ebrahimi int monitor() const { return monitor_; }
Acquire()224*f5c631daSSadaf Ebrahimi void Acquire() { monitor_++; }
Release()225*f5c631daSSadaf Ebrahimi void Release() {
226*f5c631daSSadaf Ebrahimi monitor_--;
227*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor_ >= 0);
228*f5c631daSSadaf Ebrahimi }
229*f5c631daSSadaf Ebrahimi #endif
230*f5c631daSSadaf Ebrahimi
231*f5c631daSSadaf Ebrahimi private:
232*f5c631daSSadaf Ebrahimi // The copy constructor and assignment operator are not used and the defaults
233*f5c631daSSadaf Ebrahimi // are unsafe, so disable them (without an implementation).
234*f5c631daSSadaf Ebrahimi #if __cplusplus >= 201103L
235*f5c631daSSadaf Ebrahimi InvalSet(const InvalSet& other) = delete;
236*f5c631daSSadaf Ebrahimi InvalSet operator=(const InvalSet& other) = delete;
237*f5c631daSSadaf Ebrahimi #else
238*f5c631daSSadaf Ebrahimi InvalSet(const InvalSet& other);
239*f5c631daSSadaf Ebrahimi InvalSet operator=(const InvalSet& other);
240*f5c631daSSadaf Ebrahimi #endif
241*f5c631daSSadaf Ebrahimi
242*f5c631daSSadaf Ebrahimi friend class InvalSetIterator<InvalSet<TEMPLATE_INVALSET_P_DEF> >;
243*f5c631daSSadaf Ebrahimi };
244*f5c631daSSadaf Ebrahimi
245*f5c631daSSadaf Ebrahimi
246*f5c631daSSadaf Ebrahimi template <class S>
247*f5c631daSSadaf Ebrahimi class InvalSetIterator : public std::iterator<std::forward_iterator_tag,
248*f5c631daSSadaf Ebrahimi typename S::_ElementType> {
249*f5c631daSSadaf Ebrahimi private:
250*f5c631daSSadaf Ebrahimi // Redefine types to mirror the associated set types.
251*f5c631daSSadaf Ebrahimi typedef typename S::_ElementType ElementType;
252*f5c631daSSadaf Ebrahimi typedef typename S::_KeyType KeyType;
253*f5c631daSSadaf Ebrahimi
254*f5c631daSSadaf Ebrahimi public:
255*f5c631daSSadaf Ebrahimi explicit InvalSetIterator(S* inval_set = NULL);
256*f5c631daSSadaf Ebrahimi
257*f5c631daSSadaf Ebrahimi // This class implements the standard copy-swap idiom.
258*f5c631daSSadaf Ebrahimi ~InvalSetIterator();
259*f5c631daSSadaf Ebrahimi InvalSetIterator(const InvalSetIterator<S>& other);
260*f5c631daSSadaf Ebrahimi InvalSetIterator<S>& operator=(InvalSetIterator<S> other);
261*f5c631daSSadaf Ebrahimi #if __cplusplus >= 201103L
262*f5c631daSSadaf Ebrahimi InvalSetIterator(InvalSetIterator<S>&& other) noexcept;
263*f5c631daSSadaf Ebrahimi #endif
264*f5c631daSSadaf Ebrahimi
swap(InvalSetIterator<S> & a,InvalSetIterator<S> & b)265*f5c631daSSadaf Ebrahimi friend void swap(InvalSetIterator<S>& a, InvalSetIterator<S>& b) {
266*f5c631daSSadaf Ebrahimi using std::swap;
267*f5c631daSSadaf Ebrahimi swap(a.using_vector_, b.using_vector_);
268*f5c631daSSadaf Ebrahimi swap(a.index_, b.index_);
269*f5c631daSSadaf Ebrahimi swap(a.inval_set_, b.inval_set_);
270*f5c631daSSadaf Ebrahimi }
271*f5c631daSSadaf Ebrahimi
272*f5c631daSSadaf Ebrahimi // Return true if the iterator is at the end of the set.
273*f5c631daSSadaf Ebrahimi bool Done() const;
274*f5c631daSSadaf Ebrahimi
275*f5c631daSSadaf Ebrahimi // Move this iterator to the end of the set.
276*f5c631daSSadaf Ebrahimi void Finish();
277*f5c631daSSadaf Ebrahimi
278*f5c631daSSadaf Ebrahimi // Delete the current element and advance the iterator to point to the next
279*f5c631daSSadaf Ebrahimi // element.
280*f5c631daSSadaf Ebrahimi void DeleteCurrentAndAdvance();
281*f5c631daSSadaf Ebrahimi
282*f5c631daSSadaf Ebrahimi static bool IsValid(const ElementType& element);
283*f5c631daSSadaf Ebrahimi static KeyType GetKey(const ElementType& element);
284*f5c631daSSadaf Ebrahimi
285*f5c631daSSadaf Ebrahimi // Extra helpers to support the forward-iterator interface.
286*f5c631daSSadaf Ebrahimi InvalSetIterator<S>& operator++(); // Pre-increment.
287*f5c631daSSadaf Ebrahimi InvalSetIterator<S> operator++(int); // Post-increment.
288*f5c631daSSadaf Ebrahimi bool operator==(const InvalSetIterator<S>& rhs) const;
289*f5c631daSSadaf Ebrahimi bool operator!=(const InvalSetIterator<S>& rhs) const {
290*f5c631daSSadaf Ebrahimi return !(*this == rhs);
291*f5c631daSSadaf Ebrahimi }
292*f5c631daSSadaf Ebrahimi ElementType& operator*() { return *Current(); }
293*f5c631daSSadaf Ebrahimi const ElementType& operator*() const { return *Current(); }
294*f5c631daSSadaf Ebrahimi ElementType* operator->() { return Current(); }
295*f5c631daSSadaf Ebrahimi const ElementType* operator->() const { return Current(); }
296*f5c631daSSadaf Ebrahimi
297*f5c631daSSadaf Ebrahimi protected:
298*f5c631daSSadaf Ebrahimi void MoveToValidElement();
299*f5c631daSSadaf Ebrahimi
300*f5c631daSSadaf Ebrahimi // Indicates if the iterator is looking at the vector or at the preallocated
301*f5c631daSSadaf Ebrahimi // elements.
302*f5c631daSSadaf Ebrahimi bool using_vector_;
303*f5c631daSSadaf Ebrahimi // Used when looking at the preallocated elements, or in debug mode when using
304*f5c631daSSadaf Ebrahimi // the vector to track how many times the iterator has advanced.
305*f5c631daSSadaf Ebrahimi size_t index_;
306*f5c631daSSadaf Ebrahimi typename std::vector<ElementType>::iterator iterator_;
307*f5c631daSSadaf Ebrahimi S* inval_set_;
308*f5c631daSSadaf Ebrahimi
309*f5c631daSSadaf Ebrahimi // TODO: These helpers are deprecated and will be removed in future versions
310*f5c631daSSadaf Ebrahimi // of VIXL.
311*f5c631daSSadaf Ebrahimi ElementType* Current() const;
312*f5c631daSSadaf Ebrahimi void Advance();
313*f5c631daSSadaf Ebrahimi };
314*f5c631daSSadaf Ebrahimi
315*f5c631daSSadaf Ebrahimi
316*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
InvalSet()317*f5c631daSSadaf Ebrahimi InvalSet<TEMPLATE_INVALSET_P_DEF>::InvalSet()
318*f5c631daSSadaf Ebrahimi : valid_cached_min_(false), sorted_(true), size_(0), vector_(NULL) {
319*f5c631daSSadaf Ebrahimi #ifdef VIXL_DEBUG
320*f5c631daSSadaf Ebrahimi monitor_ = 0;
321*f5c631daSSadaf Ebrahimi #endif
322*f5c631daSSadaf Ebrahimi }
323*f5c631daSSadaf Ebrahimi
324*f5c631daSSadaf Ebrahimi
325*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
~InvalSet()326*f5c631daSSadaf Ebrahimi InvalSet<TEMPLATE_INVALSET_P_DEF>::~InvalSet()
327*f5c631daSSadaf Ebrahimi VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION {
328*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor_ == 0);
329*f5c631daSSadaf Ebrahimi delete vector_;
330*f5c631daSSadaf Ebrahimi }
331*f5c631daSSadaf Ebrahimi
332*f5c631daSSadaf Ebrahimi
333*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
334*f5c631daSSadaf Ebrahimi typename InvalSet<TEMPLATE_INVALSET_P_DEF>::iterator
begin()335*f5c631daSSadaf Ebrahimi InvalSet<TEMPLATE_INVALSET_P_DEF>::begin() {
336*f5c631daSSadaf Ebrahimi return iterator(this);
337*f5c631daSSadaf Ebrahimi }
338*f5c631daSSadaf Ebrahimi
339*f5c631daSSadaf Ebrahimi
340*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
341*f5c631daSSadaf Ebrahimi typename InvalSet<TEMPLATE_INVALSET_P_DEF>::iterator
end()342*f5c631daSSadaf Ebrahimi InvalSet<TEMPLATE_INVALSET_P_DEF>::end() {
343*f5c631daSSadaf Ebrahimi iterator end(this);
344*f5c631daSSadaf Ebrahimi end.Finish();
345*f5c631daSSadaf Ebrahimi return end;
346*f5c631daSSadaf Ebrahimi }
347*f5c631daSSadaf Ebrahimi
348*f5c631daSSadaf Ebrahimi
349*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
insert(const ElementType & element)350*f5c631daSSadaf Ebrahimi void InvalSet<TEMPLATE_INVALSET_P_DEF>::insert(const ElementType& element) {
351*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor() == 0);
352*f5c631daSSadaf Ebrahimi VIXL_ASSERT(IsValid(element));
353*f5c631daSSadaf Ebrahimi VIXL_ASSERT(Search(element) == NULL);
354*f5c631daSSadaf Ebrahimi SetSorted(empty() || (sorted_ && (element > CleanBack())));
355*f5c631daSSadaf Ebrahimi if (IsUsingVector()) {
356*f5c631daSSadaf Ebrahimi vector_->push_back(element);
357*f5c631daSSadaf Ebrahimi } else {
358*f5c631daSSadaf Ebrahimi if (size_ < kNPreallocatedElements) {
359*f5c631daSSadaf Ebrahimi preallocated_[size_] = element;
360*f5c631daSSadaf Ebrahimi } else {
361*f5c631daSSadaf Ebrahimi // Transition to using the vector.
362*f5c631daSSadaf Ebrahimi vector_ =
363*f5c631daSSadaf Ebrahimi new std::vector<ElementType>(preallocated_, preallocated_ + size_);
364*f5c631daSSadaf Ebrahimi vector_->push_back(element);
365*f5c631daSSadaf Ebrahimi }
366*f5c631daSSadaf Ebrahimi }
367*f5c631daSSadaf Ebrahimi size_++;
368*f5c631daSSadaf Ebrahimi
369*f5c631daSSadaf Ebrahimi if (valid_cached_min_ && (element < GetMinElement())) {
370*f5c631daSSadaf Ebrahimi cached_min_index_ = IsUsingVector() ? vector_->size() - 1 : size_ - 1;
371*f5c631daSSadaf Ebrahimi cached_min_key_ = GetKey(element);
372*f5c631daSSadaf Ebrahimi valid_cached_min_ = true;
373*f5c631daSSadaf Ebrahimi }
374*f5c631daSSadaf Ebrahimi
375*f5c631daSSadaf Ebrahimi if (ShouldReclaimMemory()) {
376*f5c631daSSadaf Ebrahimi ReclaimMemory();
377*f5c631daSSadaf Ebrahimi }
378*f5c631daSSadaf Ebrahimi }
379*f5c631daSSadaf Ebrahimi
380*f5c631daSSadaf Ebrahimi
381*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
erase(const ElementType & element)382*f5c631daSSadaf Ebrahimi size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::erase(const ElementType& element) {
383*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor() == 0);
384*f5c631daSSadaf Ebrahimi VIXL_ASSERT(IsValid(element));
385*f5c631daSSadaf Ebrahimi ElementType* local_element = Search(element);
386*f5c631daSSadaf Ebrahimi if (local_element != NULL) {
387*f5c631daSSadaf Ebrahimi EraseInternal(local_element);
388*f5c631daSSadaf Ebrahimi return 1;
389*f5c631daSSadaf Ebrahimi }
390*f5c631daSSadaf Ebrahimi return 0;
391*f5c631daSSadaf Ebrahimi }
392*f5c631daSSadaf Ebrahimi
393*f5c631daSSadaf Ebrahimi
394*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
Search(const ElementType & element)395*f5c631daSSadaf Ebrahimi ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::Search(
396*f5c631daSSadaf Ebrahimi const ElementType& element) {
397*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor() == 0);
398*f5c631daSSadaf Ebrahimi if (empty()) {
399*f5c631daSSadaf Ebrahimi return NULL;
400*f5c631daSSadaf Ebrahimi }
401*f5c631daSSadaf Ebrahimi if (ShouldReclaimMemory()) {
402*f5c631daSSadaf Ebrahimi ReclaimMemory();
403*f5c631daSSadaf Ebrahimi }
404*f5c631daSSadaf Ebrahimi if (!sorted_) {
405*f5c631daSSadaf Ebrahimi Sort(kHardSort);
406*f5c631daSSadaf Ebrahimi }
407*f5c631daSSadaf Ebrahimi if (!valid_cached_min_) {
408*f5c631daSSadaf Ebrahimi CacheMinElement();
409*f5c631daSSadaf Ebrahimi }
410*f5c631daSSadaf Ebrahimi return BinarySearch(element, GetElementAt(cached_min_index_), StorageEnd());
411*f5c631daSSadaf Ebrahimi }
412*f5c631daSSadaf Ebrahimi
413*f5c631daSSadaf Ebrahimi
414*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
size()415*f5c631daSSadaf Ebrahimi size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::size() const {
416*f5c631daSSadaf Ebrahimi return size_;
417*f5c631daSSadaf Ebrahimi }
418*f5c631daSSadaf Ebrahimi
419*f5c631daSSadaf Ebrahimi
420*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
empty()421*f5c631daSSadaf Ebrahimi bool InvalSet<TEMPLATE_INVALSET_P_DEF>::empty() const {
422*f5c631daSSadaf Ebrahimi return size_ == 0;
423*f5c631daSSadaf Ebrahimi }
424*f5c631daSSadaf Ebrahimi
425*f5c631daSSadaf Ebrahimi
426*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
clear()427*f5c631daSSadaf Ebrahimi void InvalSet<TEMPLATE_INVALSET_P_DEF>::clear() {
428*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor() == 0);
429*f5c631daSSadaf Ebrahimi size_ = 0;
430*f5c631daSSadaf Ebrahimi if (IsUsingVector()) {
431*f5c631daSSadaf Ebrahimi vector_->clear();
432*f5c631daSSadaf Ebrahimi }
433*f5c631daSSadaf Ebrahimi SetSorted(true);
434*f5c631daSSadaf Ebrahimi valid_cached_min_ = false;
435*f5c631daSSadaf Ebrahimi }
436*f5c631daSSadaf Ebrahimi
437*f5c631daSSadaf Ebrahimi
438*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
GetMinElement()439*f5c631daSSadaf Ebrahimi const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::GetMinElement() {
440*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor() == 0);
441*f5c631daSSadaf Ebrahimi VIXL_ASSERT(!empty());
442*f5c631daSSadaf Ebrahimi CacheMinElement();
443*f5c631daSSadaf Ebrahimi return *GetElementAt(cached_min_index_);
444*f5c631daSSadaf Ebrahimi }
445*f5c631daSSadaf Ebrahimi
446*f5c631daSSadaf Ebrahimi
447*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
GetMinElementKey()448*f5c631daSSadaf Ebrahimi KeyType InvalSet<TEMPLATE_INVALSET_P_DEF>::GetMinElementKey() {
449*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor() == 0);
450*f5c631daSSadaf Ebrahimi if (valid_cached_min_) {
451*f5c631daSSadaf Ebrahimi return cached_min_key_;
452*f5c631daSSadaf Ebrahimi } else {
453*f5c631daSSadaf Ebrahimi return GetKey(GetMinElement());
454*f5c631daSSadaf Ebrahimi }
455*f5c631daSSadaf Ebrahimi }
456*f5c631daSSadaf Ebrahimi
457*f5c631daSSadaf Ebrahimi
458*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
IsValid(const ElementType & element)459*f5c631daSSadaf Ebrahimi bool InvalSet<TEMPLATE_INVALSET_P_DEF>::IsValid(const ElementType& element) {
460*f5c631daSSadaf Ebrahimi return GetKey(element) != kInvalidKey;
461*f5c631daSSadaf Ebrahimi }
462*f5c631daSSadaf Ebrahimi
463*f5c631daSSadaf Ebrahimi
464*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
EraseInternal(ElementType * element)465*f5c631daSSadaf Ebrahimi void InvalSet<TEMPLATE_INVALSET_P_DEF>::EraseInternal(ElementType* element) {
466*f5c631daSSadaf Ebrahimi // Note that this function must be safe even while an iterator has acquired
467*f5c631daSSadaf Ebrahimi // this set.
468*f5c631daSSadaf Ebrahimi VIXL_ASSERT(element != NULL);
469*f5c631daSSadaf Ebrahimi size_t deleted_index = GetElementIndex(element);
470*f5c631daSSadaf Ebrahimi if (IsUsingVector()) {
471*f5c631daSSadaf Ebrahimi VIXL_ASSERT((&(vector_->front()) <= element) &&
472*f5c631daSSadaf Ebrahimi (element <= &(vector_->back())));
473*f5c631daSSadaf Ebrahimi SetKey(element, kInvalidKey);
474*f5c631daSSadaf Ebrahimi } else {
475*f5c631daSSadaf Ebrahimi VIXL_ASSERT((preallocated_ <= element) &&
476*f5c631daSSadaf Ebrahimi (element < (preallocated_ + kNPreallocatedElements)));
477*f5c631daSSadaf Ebrahimi ElementType* end = preallocated_ + kNPreallocatedElements;
478*f5c631daSSadaf Ebrahimi size_t copy_size = sizeof(*element) * (end - element - 1);
479*f5c631daSSadaf Ebrahimi memmove(element, element + 1, copy_size);
480*f5c631daSSadaf Ebrahimi }
481*f5c631daSSadaf Ebrahimi size_--;
482*f5c631daSSadaf Ebrahimi
483*f5c631daSSadaf Ebrahimi if (valid_cached_min_ && (deleted_index == cached_min_index_)) {
484*f5c631daSSadaf Ebrahimi if (sorted_ && !empty()) {
485*f5c631daSSadaf Ebrahimi const ElementType* min = GetFirstValidElement(element, StorageEnd());
486*f5c631daSSadaf Ebrahimi cached_min_index_ = GetElementIndex(min);
487*f5c631daSSadaf Ebrahimi cached_min_key_ = GetKey(*min);
488*f5c631daSSadaf Ebrahimi valid_cached_min_ = true;
489*f5c631daSSadaf Ebrahimi } else {
490*f5c631daSSadaf Ebrahimi valid_cached_min_ = false;
491*f5c631daSSadaf Ebrahimi }
492*f5c631daSSadaf Ebrahimi }
493*f5c631daSSadaf Ebrahimi }
494*f5c631daSSadaf Ebrahimi
495*f5c631daSSadaf Ebrahimi
496*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
BinarySearch(const ElementType & element,ElementType * start,ElementType * end)497*f5c631daSSadaf Ebrahimi ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::BinarySearch(
498*f5c631daSSadaf Ebrahimi const ElementType& element, ElementType* start, ElementType* end) const {
499*f5c631daSSadaf Ebrahimi if (start == end) {
500*f5c631daSSadaf Ebrahimi return NULL;
501*f5c631daSSadaf Ebrahimi }
502*f5c631daSSadaf Ebrahimi VIXL_ASSERT(sorted_);
503*f5c631daSSadaf Ebrahimi VIXL_ASSERT(start < end);
504*f5c631daSSadaf Ebrahimi VIXL_ASSERT(!empty());
505*f5c631daSSadaf Ebrahimi
506*f5c631daSSadaf Ebrahimi // Perform a binary search through the elements while ignoring invalid
507*f5c631daSSadaf Ebrahimi // elements.
508*f5c631daSSadaf Ebrahimi ElementType* elements = start;
509*f5c631daSSadaf Ebrahimi size_t low = 0;
510*f5c631daSSadaf Ebrahimi size_t high = (end - start) - 1;
511*f5c631daSSadaf Ebrahimi while (low < high) {
512*f5c631daSSadaf Ebrahimi // Find valid bounds.
513*f5c631daSSadaf Ebrahimi while (!IsValid(elements[low]) && (low < high)) ++low;
514*f5c631daSSadaf Ebrahimi while (!IsValid(elements[high]) && (low < high)) --high;
515*f5c631daSSadaf Ebrahimi VIXL_ASSERT(low <= high);
516*f5c631daSSadaf Ebrahimi // Avoid overflow when computing the middle index.
517*f5c631daSSadaf Ebrahimi size_t middle = low + (high - low) / 2;
518*f5c631daSSadaf Ebrahimi if ((middle == low) || (middle == high)) {
519*f5c631daSSadaf Ebrahimi break;
520*f5c631daSSadaf Ebrahimi }
521*f5c631daSSadaf Ebrahimi while ((middle < high - 1) && !IsValid(elements[middle])) ++middle;
522*f5c631daSSadaf Ebrahimi while ((low + 1 < middle) && !IsValid(elements[middle])) --middle;
523*f5c631daSSadaf Ebrahimi if (!IsValid(elements[middle])) {
524*f5c631daSSadaf Ebrahimi break;
525*f5c631daSSadaf Ebrahimi }
526*f5c631daSSadaf Ebrahimi if (elements[middle] < element) {
527*f5c631daSSadaf Ebrahimi low = middle;
528*f5c631daSSadaf Ebrahimi } else {
529*f5c631daSSadaf Ebrahimi high = middle;
530*f5c631daSSadaf Ebrahimi }
531*f5c631daSSadaf Ebrahimi }
532*f5c631daSSadaf Ebrahimi
533*f5c631daSSadaf Ebrahimi if (elements[low] == element) return &elements[low];
534*f5c631daSSadaf Ebrahimi if (elements[high] == element) return &elements[high];
535*f5c631daSSadaf Ebrahimi return NULL;
536*f5c631daSSadaf Ebrahimi }
537*f5c631daSSadaf Ebrahimi
538*f5c631daSSadaf Ebrahimi
539*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
Sort(SortType sort_type)540*f5c631daSSadaf Ebrahimi void InvalSet<TEMPLATE_INVALSET_P_DEF>::Sort(SortType sort_type) {
541*f5c631daSSadaf Ebrahimi if (sort_type == kSoftSort) {
542*f5c631daSSadaf Ebrahimi if (sorted_) {
543*f5c631daSSadaf Ebrahimi return;
544*f5c631daSSadaf Ebrahimi }
545*f5c631daSSadaf Ebrahimi }
546*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor() == 0);
547*f5c631daSSadaf Ebrahimi if (empty()) {
548*f5c631daSSadaf Ebrahimi return;
549*f5c631daSSadaf Ebrahimi }
550*f5c631daSSadaf Ebrahimi
551*f5c631daSSadaf Ebrahimi Clean();
552*f5c631daSSadaf Ebrahimi std::sort(StorageBegin(), StorageEnd());
553*f5c631daSSadaf Ebrahimi
554*f5c631daSSadaf Ebrahimi SetSorted(true);
555*f5c631daSSadaf Ebrahimi cached_min_index_ = 0;
556*f5c631daSSadaf Ebrahimi cached_min_key_ = GetKey(Front());
557*f5c631daSSadaf Ebrahimi valid_cached_min_ = true;
558*f5c631daSSadaf Ebrahimi }
559*f5c631daSSadaf Ebrahimi
560*f5c631daSSadaf Ebrahimi
561*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
Clean()562*f5c631daSSadaf Ebrahimi void InvalSet<TEMPLATE_INVALSET_P_DEF>::Clean() {
563*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor() == 0);
564*f5c631daSSadaf Ebrahimi if (empty() || !IsUsingVector()) {
565*f5c631daSSadaf Ebrahimi return;
566*f5c631daSSadaf Ebrahimi }
567*f5c631daSSadaf Ebrahimi // Manually iterate through the vector storage to discard invalid elements.
568*f5c631daSSadaf Ebrahimi ElementType* start = &(vector_->front());
569*f5c631daSSadaf Ebrahimi ElementType* end = start + vector_->size();
570*f5c631daSSadaf Ebrahimi ElementType* c = start;
571*f5c631daSSadaf Ebrahimi ElementType* first_invalid;
572*f5c631daSSadaf Ebrahimi ElementType* first_valid;
573*f5c631daSSadaf Ebrahimi ElementType* next_invalid;
574*f5c631daSSadaf Ebrahimi
575*f5c631daSSadaf Ebrahimi while ((c < end) && IsValid(*c)) c++;
576*f5c631daSSadaf Ebrahimi first_invalid = c;
577*f5c631daSSadaf Ebrahimi
578*f5c631daSSadaf Ebrahimi while (c < end) {
579*f5c631daSSadaf Ebrahimi while ((c < end) && !IsValid(*c)) c++;
580*f5c631daSSadaf Ebrahimi first_valid = c;
581*f5c631daSSadaf Ebrahimi while ((c < end) && IsValid(*c)) c++;
582*f5c631daSSadaf Ebrahimi next_invalid = c;
583*f5c631daSSadaf Ebrahimi
584*f5c631daSSadaf Ebrahimi ptrdiff_t n_moved_elements = (next_invalid - first_valid);
585*f5c631daSSadaf Ebrahimi memmove(first_invalid, first_valid, n_moved_elements * sizeof(*c));
586*f5c631daSSadaf Ebrahimi first_invalid = first_invalid + n_moved_elements;
587*f5c631daSSadaf Ebrahimi c = next_invalid;
588*f5c631daSSadaf Ebrahimi }
589*f5c631daSSadaf Ebrahimi
590*f5c631daSSadaf Ebrahimi // Delete the trailing invalid elements.
591*f5c631daSSadaf Ebrahimi vector_->erase(vector_->begin() + (first_invalid - start), vector_->end());
592*f5c631daSSadaf Ebrahimi VIXL_ASSERT(vector_->size() == size_);
593*f5c631daSSadaf Ebrahimi
594*f5c631daSSadaf Ebrahimi if (sorted_) {
595*f5c631daSSadaf Ebrahimi valid_cached_min_ = true;
596*f5c631daSSadaf Ebrahimi cached_min_index_ = 0;
597*f5c631daSSadaf Ebrahimi cached_min_key_ = GetKey(*GetElementAt(0));
598*f5c631daSSadaf Ebrahimi } else {
599*f5c631daSSadaf Ebrahimi valid_cached_min_ = false;
600*f5c631daSSadaf Ebrahimi }
601*f5c631daSSadaf Ebrahimi }
602*f5c631daSSadaf Ebrahimi
603*f5c631daSSadaf Ebrahimi
604*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
Front()605*f5c631daSSadaf Ebrahimi const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Front() const {
606*f5c631daSSadaf Ebrahimi VIXL_ASSERT(!empty());
607*f5c631daSSadaf Ebrahimi return IsUsingVector() ? vector_->front() : preallocated_[0];
608*f5c631daSSadaf Ebrahimi }
609*f5c631daSSadaf Ebrahimi
610*f5c631daSSadaf Ebrahimi
611*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
Back()612*f5c631daSSadaf Ebrahimi const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::Back() const {
613*f5c631daSSadaf Ebrahimi VIXL_ASSERT(!empty());
614*f5c631daSSadaf Ebrahimi return IsUsingVector() ? vector_->back() : preallocated_[size_ - 1];
615*f5c631daSSadaf Ebrahimi }
616*f5c631daSSadaf Ebrahimi
617*f5c631daSSadaf Ebrahimi
618*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
CleanBack()619*f5c631daSSadaf Ebrahimi const ElementType InvalSet<TEMPLATE_INVALSET_P_DEF>::CleanBack() {
620*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor() == 0);
621*f5c631daSSadaf Ebrahimi if (IsUsingVector()) {
622*f5c631daSSadaf Ebrahimi // Delete the invalid trailing elements.
623*f5c631daSSadaf Ebrahimi typename std::vector<ElementType>::reverse_iterator it = vector_->rbegin();
624*f5c631daSSadaf Ebrahimi while (!IsValid(*it)) {
625*f5c631daSSadaf Ebrahimi it++;
626*f5c631daSSadaf Ebrahimi }
627*f5c631daSSadaf Ebrahimi vector_->erase(it.base(), vector_->end());
628*f5c631daSSadaf Ebrahimi }
629*f5c631daSSadaf Ebrahimi return Back();
630*f5c631daSSadaf Ebrahimi }
631*f5c631daSSadaf Ebrahimi
632*f5c631daSSadaf Ebrahimi
633*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
StorageBegin()634*f5c631daSSadaf Ebrahimi const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() const {
635*f5c631daSSadaf Ebrahimi return IsUsingVector() ? &(vector_->front()) : preallocated_;
636*f5c631daSSadaf Ebrahimi }
637*f5c631daSSadaf Ebrahimi
638*f5c631daSSadaf Ebrahimi
639*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
StorageEnd()640*f5c631daSSadaf Ebrahimi const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() const {
641*f5c631daSSadaf Ebrahimi return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_;
642*f5c631daSSadaf Ebrahimi }
643*f5c631daSSadaf Ebrahimi
644*f5c631daSSadaf Ebrahimi
645*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
StorageBegin()646*f5c631daSSadaf Ebrahimi ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageBegin() {
647*f5c631daSSadaf Ebrahimi return IsUsingVector() ? &(vector_->front()) : preallocated_;
648*f5c631daSSadaf Ebrahimi }
649*f5c631daSSadaf Ebrahimi
650*f5c631daSSadaf Ebrahimi
651*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
StorageEnd()652*f5c631daSSadaf Ebrahimi ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::StorageEnd() {
653*f5c631daSSadaf Ebrahimi return IsUsingVector() ? &(vector_->back()) + 1 : preallocated_ + size_;
654*f5c631daSSadaf Ebrahimi }
655*f5c631daSSadaf Ebrahimi
656*f5c631daSSadaf Ebrahimi
657*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
GetElementIndex(const ElementType * element)658*f5c631daSSadaf Ebrahimi size_t InvalSet<TEMPLATE_INVALSET_P_DEF>::GetElementIndex(
659*f5c631daSSadaf Ebrahimi const ElementType* element) const {
660*f5c631daSSadaf Ebrahimi VIXL_ASSERT((StorageBegin() <= element) && (element < StorageEnd()));
661*f5c631daSSadaf Ebrahimi return element - StorageBegin();
662*f5c631daSSadaf Ebrahimi }
663*f5c631daSSadaf Ebrahimi
664*f5c631daSSadaf Ebrahimi
665*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
GetElementAt(size_t index)666*f5c631daSSadaf Ebrahimi const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::GetElementAt(
667*f5c631daSSadaf Ebrahimi size_t index) const {
668*f5c631daSSadaf Ebrahimi VIXL_ASSERT((IsUsingVector() && (index < vector_->size())) ||
669*f5c631daSSadaf Ebrahimi (index < size_));
670*f5c631daSSadaf Ebrahimi return StorageBegin() + index;
671*f5c631daSSadaf Ebrahimi }
672*f5c631daSSadaf Ebrahimi
673*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
GetElementAt(size_t index)674*f5c631daSSadaf Ebrahimi ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::GetElementAt(size_t index) {
675*f5c631daSSadaf Ebrahimi VIXL_ASSERT((IsUsingVector() && (index < vector_->size())) ||
676*f5c631daSSadaf Ebrahimi (index < size_));
677*f5c631daSSadaf Ebrahimi return StorageBegin() + index;
678*f5c631daSSadaf Ebrahimi }
679*f5c631daSSadaf Ebrahimi
680*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
GetFirstValidElement(const ElementType * from,const ElementType * end)681*f5c631daSSadaf Ebrahimi const ElementType* InvalSet<TEMPLATE_INVALSET_P_DEF>::GetFirstValidElement(
682*f5c631daSSadaf Ebrahimi const ElementType* from, const ElementType* end) {
683*f5c631daSSadaf Ebrahimi while ((from < end) && !IsValid(*from)) {
684*f5c631daSSadaf Ebrahimi from++;
685*f5c631daSSadaf Ebrahimi }
686*f5c631daSSadaf Ebrahimi return from;
687*f5c631daSSadaf Ebrahimi }
688*f5c631daSSadaf Ebrahimi
689*f5c631daSSadaf Ebrahimi
690*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
CacheMinElement()691*f5c631daSSadaf Ebrahimi void InvalSet<TEMPLATE_INVALSET_P_DEF>::CacheMinElement() {
692*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor() == 0);
693*f5c631daSSadaf Ebrahimi VIXL_ASSERT(!empty());
694*f5c631daSSadaf Ebrahimi
695*f5c631daSSadaf Ebrahimi if (valid_cached_min_) {
696*f5c631daSSadaf Ebrahimi return;
697*f5c631daSSadaf Ebrahimi }
698*f5c631daSSadaf Ebrahimi
699*f5c631daSSadaf Ebrahimi if (sorted_) {
700*f5c631daSSadaf Ebrahimi const ElementType* min = GetFirstValidElement(StorageBegin(), StorageEnd());
701*f5c631daSSadaf Ebrahimi cached_min_index_ = GetElementIndex(min);
702*f5c631daSSadaf Ebrahimi cached_min_key_ = GetKey(*min);
703*f5c631daSSadaf Ebrahimi valid_cached_min_ = true;
704*f5c631daSSadaf Ebrahimi } else {
705*f5c631daSSadaf Ebrahimi Sort(kHardSort);
706*f5c631daSSadaf Ebrahimi }
707*f5c631daSSadaf Ebrahimi VIXL_ASSERT(valid_cached_min_);
708*f5c631daSSadaf Ebrahimi }
709*f5c631daSSadaf Ebrahimi
710*f5c631daSSadaf Ebrahimi
711*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
ShouldReclaimMemory()712*f5c631daSSadaf Ebrahimi bool InvalSet<TEMPLATE_INVALSET_P_DEF>::ShouldReclaimMemory() const {
713*f5c631daSSadaf Ebrahimi if (!IsUsingVector()) {
714*f5c631daSSadaf Ebrahimi return false;
715*f5c631daSSadaf Ebrahimi }
716*f5c631daSSadaf Ebrahimi size_t n_invalid_elements = vector_->size() - size_;
717*f5c631daSSadaf Ebrahimi return (n_invalid_elements > RECLAIM_FROM) &&
718*f5c631daSSadaf Ebrahimi (n_invalid_elements > vector_->size() / RECLAIM_FACTOR);
719*f5c631daSSadaf Ebrahimi }
720*f5c631daSSadaf Ebrahimi
721*f5c631daSSadaf Ebrahimi
722*f5c631daSSadaf Ebrahimi template <TEMPLATE_INVALSET_P_DECL>
ReclaimMemory()723*f5c631daSSadaf Ebrahimi void InvalSet<TEMPLATE_INVALSET_P_DEF>::ReclaimMemory() {
724*f5c631daSSadaf Ebrahimi VIXL_ASSERT(monitor() == 0);
725*f5c631daSSadaf Ebrahimi Clean();
726*f5c631daSSadaf Ebrahimi }
727*f5c631daSSadaf Ebrahimi
728*f5c631daSSadaf Ebrahimi
729*f5c631daSSadaf Ebrahimi template <class S>
InvalSetIterator(S * inval_set)730*f5c631daSSadaf Ebrahimi InvalSetIterator<S>::InvalSetIterator(S* inval_set)
731*f5c631daSSadaf Ebrahimi : using_vector_((inval_set != NULL) && inval_set->IsUsingVector()),
732*f5c631daSSadaf Ebrahimi index_(0),
733*f5c631daSSadaf Ebrahimi inval_set_(inval_set) {
734*f5c631daSSadaf Ebrahimi if (inval_set != NULL) {
735*f5c631daSSadaf Ebrahimi inval_set->Sort(S::kSoftSort);
736*f5c631daSSadaf Ebrahimi #ifdef VIXL_DEBUG
737*f5c631daSSadaf Ebrahimi inval_set->Acquire();
738*f5c631daSSadaf Ebrahimi #endif
739*f5c631daSSadaf Ebrahimi if (using_vector_) {
740*f5c631daSSadaf Ebrahimi iterator_ = typename std::vector<ElementType>::iterator(
741*f5c631daSSadaf Ebrahimi inval_set_->vector_->begin());
742*f5c631daSSadaf Ebrahimi }
743*f5c631daSSadaf Ebrahimi MoveToValidElement();
744*f5c631daSSadaf Ebrahimi }
745*f5c631daSSadaf Ebrahimi }
746*f5c631daSSadaf Ebrahimi
747*f5c631daSSadaf Ebrahimi
748*f5c631daSSadaf Ebrahimi template <class S>
~InvalSetIterator()749*f5c631daSSadaf Ebrahimi InvalSetIterator<S>::~InvalSetIterator() {
750*f5c631daSSadaf Ebrahimi #ifdef VIXL_DEBUG
751*f5c631daSSadaf Ebrahimi if (inval_set_ != NULL) inval_set_->Release();
752*f5c631daSSadaf Ebrahimi #endif
753*f5c631daSSadaf Ebrahimi }
754*f5c631daSSadaf Ebrahimi
755*f5c631daSSadaf Ebrahimi
756*f5c631daSSadaf Ebrahimi template <class S>
Current()757*f5c631daSSadaf Ebrahimi typename S::_ElementType* InvalSetIterator<S>::Current() const {
758*f5c631daSSadaf Ebrahimi VIXL_ASSERT(!Done());
759*f5c631daSSadaf Ebrahimi if (using_vector_) {
760*f5c631daSSadaf Ebrahimi return &(*iterator_);
761*f5c631daSSadaf Ebrahimi } else {
762*f5c631daSSadaf Ebrahimi return &(inval_set_->preallocated_[index_]);
763*f5c631daSSadaf Ebrahimi }
764*f5c631daSSadaf Ebrahimi }
765*f5c631daSSadaf Ebrahimi
766*f5c631daSSadaf Ebrahimi
767*f5c631daSSadaf Ebrahimi template <class S>
Advance()768*f5c631daSSadaf Ebrahimi void InvalSetIterator<S>::Advance() {
769*f5c631daSSadaf Ebrahimi ++(*this);
770*f5c631daSSadaf Ebrahimi }
771*f5c631daSSadaf Ebrahimi
772*f5c631daSSadaf Ebrahimi
773*f5c631daSSadaf Ebrahimi template <class S>
Done()774*f5c631daSSadaf Ebrahimi bool InvalSetIterator<S>::Done() const {
775*f5c631daSSadaf Ebrahimi if (using_vector_) {
776*f5c631daSSadaf Ebrahimi bool done = (iterator_ == inval_set_->vector_->end());
777*f5c631daSSadaf Ebrahimi VIXL_ASSERT(done == (index_ == inval_set_->size()));
778*f5c631daSSadaf Ebrahimi return done;
779*f5c631daSSadaf Ebrahimi } else {
780*f5c631daSSadaf Ebrahimi return index_ == inval_set_->size();
781*f5c631daSSadaf Ebrahimi }
782*f5c631daSSadaf Ebrahimi }
783*f5c631daSSadaf Ebrahimi
784*f5c631daSSadaf Ebrahimi
785*f5c631daSSadaf Ebrahimi template <class S>
Finish()786*f5c631daSSadaf Ebrahimi void InvalSetIterator<S>::Finish() {
787*f5c631daSSadaf Ebrahimi VIXL_ASSERT(inval_set_->sorted_);
788*f5c631daSSadaf Ebrahimi if (using_vector_) {
789*f5c631daSSadaf Ebrahimi iterator_ = inval_set_->vector_->end();
790*f5c631daSSadaf Ebrahimi }
791*f5c631daSSadaf Ebrahimi index_ = inval_set_->size();
792*f5c631daSSadaf Ebrahimi }
793*f5c631daSSadaf Ebrahimi
794*f5c631daSSadaf Ebrahimi
795*f5c631daSSadaf Ebrahimi template <class S>
DeleteCurrentAndAdvance()796*f5c631daSSadaf Ebrahimi void InvalSetIterator<S>::DeleteCurrentAndAdvance() {
797*f5c631daSSadaf Ebrahimi if (using_vector_) {
798*f5c631daSSadaf Ebrahimi inval_set_->EraseInternal(&(*iterator_));
799*f5c631daSSadaf Ebrahimi MoveToValidElement();
800*f5c631daSSadaf Ebrahimi } else {
801*f5c631daSSadaf Ebrahimi inval_set_->EraseInternal(inval_set_->preallocated_ + index_);
802*f5c631daSSadaf Ebrahimi }
803*f5c631daSSadaf Ebrahimi }
804*f5c631daSSadaf Ebrahimi
805*f5c631daSSadaf Ebrahimi
806*f5c631daSSadaf Ebrahimi template <class S>
IsValid(const ElementType & element)807*f5c631daSSadaf Ebrahimi bool InvalSetIterator<S>::IsValid(const ElementType& element) {
808*f5c631daSSadaf Ebrahimi return S::IsValid(element);
809*f5c631daSSadaf Ebrahimi }
810*f5c631daSSadaf Ebrahimi
811*f5c631daSSadaf Ebrahimi
812*f5c631daSSadaf Ebrahimi template <class S>
GetKey(const ElementType & element)813*f5c631daSSadaf Ebrahimi typename S::_KeyType InvalSetIterator<S>::GetKey(const ElementType& element) {
814*f5c631daSSadaf Ebrahimi return S::GetKey(element);
815*f5c631daSSadaf Ebrahimi }
816*f5c631daSSadaf Ebrahimi
817*f5c631daSSadaf Ebrahimi
818*f5c631daSSadaf Ebrahimi template <class S>
MoveToValidElement()819*f5c631daSSadaf Ebrahimi void InvalSetIterator<S>::MoveToValidElement() {
820*f5c631daSSadaf Ebrahimi if (using_vector_) {
821*f5c631daSSadaf Ebrahimi while ((iterator_ != inval_set_->vector_->end()) && !IsValid(*iterator_)) {
822*f5c631daSSadaf Ebrahimi iterator_++;
823*f5c631daSSadaf Ebrahimi }
824*f5c631daSSadaf Ebrahimi } else {
825*f5c631daSSadaf Ebrahimi VIXL_ASSERT(inval_set_->empty() || IsValid(inval_set_->preallocated_[0]));
826*f5c631daSSadaf Ebrahimi // Nothing to do.
827*f5c631daSSadaf Ebrahimi }
828*f5c631daSSadaf Ebrahimi }
829*f5c631daSSadaf Ebrahimi
830*f5c631daSSadaf Ebrahimi
831*f5c631daSSadaf Ebrahimi template <class S>
InvalSetIterator(const InvalSetIterator<S> & other)832*f5c631daSSadaf Ebrahimi InvalSetIterator<S>::InvalSetIterator(const InvalSetIterator<S>& other)
833*f5c631daSSadaf Ebrahimi : using_vector_(other.using_vector_),
834*f5c631daSSadaf Ebrahimi index_(other.index_),
835*f5c631daSSadaf Ebrahimi inval_set_(other.inval_set_) {
836*f5c631daSSadaf Ebrahimi #ifdef VIXL_DEBUG
837*f5c631daSSadaf Ebrahimi if (inval_set_ != NULL) inval_set_->Acquire();
838*f5c631daSSadaf Ebrahimi #endif
839*f5c631daSSadaf Ebrahimi }
840*f5c631daSSadaf Ebrahimi
841*f5c631daSSadaf Ebrahimi
842*f5c631daSSadaf Ebrahimi #if __cplusplus >= 201103L
843*f5c631daSSadaf Ebrahimi template <class S>
InvalSetIterator(InvalSetIterator<S> && other)844*f5c631daSSadaf Ebrahimi InvalSetIterator<S>::InvalSetIterator(InvalSetIterator<S>&& other) noexcept
845*f5c631daSSadaf Ebrahimi : using_vector_(false), index_(0), inval_set_(NULL) {
846*f5c631daSSadaf Ebrahimi swap(*this, other);
847*f5c631daSSadaf Ebrahimi }
848*f5c631daSSadaf Ebrahimi #endif
849*f5c631daSSadaf Ebrahimi
850*f5c631daSSadaf Ebrahimi
851*f5c631daSSadaf Ebrahimi template <class S>
852*f5c631daSSadaf Ebrahimi InvalSetIterator<S>& InvalSetIterator<S>::operator=(InvalSetIterator<S> other) {
853*f5c631daSSadaf Ebrahimi swap(*this, other);
854*f5c631daSSadaf Ebrahimi return *this;
855*f5c631daSSadaf Ebrahimi }
856*f5c631daSSadaf Ebrahimi
857*f5c631daSSadaf Ebrahimi
858*f5c631daSSadaf Ebrahimi template <class S>
859*f5c631daSSadaf Ebrahimi bool InvalSetIterator<S>::operator==(const InvalSetIterator<S>& rhs) const {
860*f5c631daSSadaf Ebrahimi bool equal = (inval_set_ == rhs.inval_set_);
861*f5c631daSSadaf Ebrahimi
862*f5c631daSSadaf Ebrahimi // If the inval_set_ matches, using_vector_ must also match.
863*f5c631daSSadaf Ebrahimi VIXL_ASSERT(!equal || (using_vector_ == rhs.using_vector_));
864*f5c631daSSadaf Ebrahimi
865*f5c631daSSadaf Ebrahimi if (using_vector_) {
866*f5c631daSSadaf Ebrahimi equal = equal && (iterator_ == rhs.iterator_);
867*f5c631daSSadaf Ebrahimi // In debug mode, index_ is maintained even with using_vector_.
868*f5c631daSSadaf Ebrahimi VIXL_ASSERT(!equal || (index_ == rhs.index_));
869*f5c631daSSadaf Ebrahimi } else {
870*f5c631daSSadaf Ebrahimi equal = equal && (index_ == rhs.index_);
871*f5c631daSSadaf Ebrahimi #ifdef DEBUG
872*f5c631daSSadaf Ebrahimi // If not using_vector_, iterator_ should be default-initialised.
873*f5c631daSSadaf Ebrahimi typename std::vector<ElementType>::iterator default_iterator;
874*f5c631daSSadaf Ebrahimi VIXL_ASSERT(iterator_ == default_iterator);
875*f5c631daSSadaf Ebrahimi VIXL_ASSERT(rhs.iterator_ == default_iterator);
876*f5c631daSSadaf Ebrahimi #endif
877*f5c631daSSadaf Ebrahimi }
878*f5c631daSSadaf Ebrahimi return equal;
879*f5c631daSSadaf Ebrahimi }
880*f5c631daSSadaf Ebrahimi
881*f5c631daSSadaf Ebrahimi
882*f5c631daSSadaf Ebrahimi template <class S>
883*f5c631daSSadaf Ebrahimi InvalSetIterator<S>& InvalSetIterator<S>::operator++() {
884*f5c631daSSadaf Ebrahimi // Pre-increment.
885*f5c631daSSadaf Ebrahimi VIXL_ASSERT(!Done());
886*f5c631daSSadaf Ebrahimi if (using_vector_) {
887*f5c631daSSadaf Ebrahimi iterator_++;
888*f5c631daSSadaf Ebrahimi #ifdef VIXL_DEBUG
889*f5c631daSSadaf Ebrahimi index_++;
890*f5c631daSSadaf Ebrahimi #endif
891*f5c631daSSadaf Ebrahimi MoveToValidElement();
892*f5c631daSSadaf Ebrahimi } else {
893*f5c631daSSadaf Ebrahimi index_++;
894*f5c631daSSadaf Ebrahimi }
895*f5c631daSSadaf Ebrahimi return *this;
896*f5c631daSSadaf Ebrahimi }
897*f5c631daSSadaf Ebrahimi
898*f5c631daSSadaf Ebrahimi
899*f5c631daSSadaf Ebrahimi template <class S>
900*f5c631daSSadaf Ebrahimi InvalSetIterator<S> InvalSetIterator<S>::operator++(int /* unused */) {
901*f5c631daSSadaf Ebrahimi // Post-increment.
902*f5c631daSSadaf Ebrahimi VIXL_ASSERT(!Done());
903*f5c631daSSadaf Ebrahimi InvalSetIterator<S> old(*this);
904*f5c631daSSadaf Ebrahimi ++(*this);
905*f5c631daSSadaf Ebrahimi return old;
906*f5c631daSSadaf Ebrahimi }
907*f5c631daSSadaf Ebrahimi
908*f5c631daSSadaf Ebrahimi
909*f5c631daSSadaf Ebrahimi #undef TEMPLATE_INVALSET_P_DECL
910*f5c631daSSadaf Ebrahimi #undef TEMPLATE_INVALSET_P_DEF
911*f5c631daSSadaf Ebrahimi
912*f5c631daSSadaf Ebrahimi } // namespace vixl
913*f5c631daSSadaf Ebrahimi
914*f5c631daSSadaf Ebrahimi #endif // VIXL_INVALSET_H_
915