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