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