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