1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // FastVector.h:
7 // A vector class with a initial fixed size and variable growth.
8 // Based on FixedVector.
9 //
10
11 #ifndef COMMON_FASTVECTOR_H_
12 #define COMMON_FASTVECTOR_H_
13
14 #include "bitset_utils.h"
15 #include "common/debug.h"
16
17 #include <algorithm>
18 #include <array>
19 #include <initializer_list>
20
21 namespace angle
22 {
23 template <class T, size_t N, class Storage = std::array<T, N>>
24 class FastVector final
25 {
26 public:
27 using value_type = typename Storage::value_type;
28 using size_type = typename Storage::size_type;
29 using reference = typename Storage::reference;
30 using const_reference = typename Storage::const_reference;
31 using pointer = typename Storage::pointer;
32 using const_pointer = typename Storage::const_pointer;
33 using iterator = T *;
34 using const_iterator = const T *;
35
36 FastVector();
37 FastVector(size_type count, const value_type &value);
38 FastVector(size_type count);
39
40 FastVector(const FastVector<T, N, Storage> &other);
41 FastVector(FastVector<T, N, Storage> &&other);
42 FastVector(std::initializer_list<value_type> init);
43
44 template <class InputIt, std::enable_if_t<!std::is_integral<InputIt>::value, bool> = true>
45 FastVector(InputIt first, InputIt last);
46
47 FastVector<T, N, Storage> &operator=(const FastVector<T, N, Storage> &other);
48 FastVector<T, N, Storage> &operator=(FastVector<T, N, Storage> &&other);
49 FastVector<T, N, Storage> &operator=(std::initializer_list<value_type> init);
50
51 ~FastVector();
52
53 reference at(size_type pos);
54 const_reference at(size_type pos) const;
55
56 reference operator[](size_type pos);
57 const_reference operator[](size_type pos) const;
58
59 pointer data();
60 const_pointer data() const;
61
62 iterator begin();
63 const_iterator begin() const;
64
65 iterator end();
66 const_iterator end() const;
67
68 bool empty() const;
69 size_type size() const;
70
71 void clear();
72
73 void push_back(const value_type &value);
74 void push_back(value_type &&value);
75
76 template <typename... Args>
77 void emplace_back(Args &&... args);
78
79 void pop_back();
80
81 reference front();
82 const_reference front() const;
83
84 reference back();
85 const_reference back() const;
86
87 void swap(FastVector<T, N, Storage> &other);
88
89 void resize(size_type count);
90 void resize(size_type count, const value_type &value);
91
92 // Specialty function that removes a known element and might shuffle the list.
93 void remove_and_permute(const value_type &element);
94
95 private:
96 void assign_from_initializer_list(std::initializer_list<value_type> init);
97 void ensure_capacity(size_t capacity);
98 bool uses_fixed_storage() const;
99
100 Storage mFixedStorage;
101 pointer mData = mFixedStorage.data();
102 size_type mSize = 0;
103 size_type mReservedSize = N;
104 };
105
106 template <class T, size_t N, class StorageN, size_t M, class StorageM>
107 bool operator==(const FastVector<T, N, StorageN> &a, const FastVector<T, M, StorageM> &b)
108 {
109 return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
110 }
111
112 template <class T, size_t N, class StorageN, size_t M, class StorageM>
113 bool operator!=(const FastVector<T, N, StorageN> &a, const FastVector<T, M, StorageM> &b)
114 {
115 return !(a == b);
116 }
117
118 template <class T, size_t N, class Storage>
uses_fixed_storage()119 ANGLE_INLINE bool FastVector<T, N, Storage>::uses_fixed_storage() const
120 {
121 return mData == mFixedStorage.data();
122 }
123
124 template <class T, size_t N, class Storage>
FastVector()125 FastVector<T, N, Storage>::FastVector()
126 {}
127
128 template <class T, size_t N, class Storage>
FastVector(size_type count,const value_type & value)129 FastVector<T, N, Storage>::FastVector(size_type count, const value_type &value)
130 {
131 ensure_capacity(count);
132 mSize = count;
133 std::fill(begin(), end(), value);
134 }
135
136 template <class T, size_t N, class Storage>
FastVector(size_type count)137 FastVector<T, N, Storage>::FastVector(size_type count)
138 {
139 ensure_capacity(count);
140 mSize = count;
141 }
142
143 template <class T, size_t N, class Storage>
FastVector(const FastVector<T,N,Storage> & other)144 FastVector<T, N, Storage>::FastVector(const FastVector<T, N, Storage> &other)
145 : FastVector(other.begin(), other.end())
146 {}
147
148 template <class T, size_t N, class Storage>
FastVector(FastVector<T,N,Storage> && other)149 FastVector<T, N, Storage>::FastVector(FastVector<T, N, Storage> &&other) : FastVector()
150 {
151 swap(other);
152 }
153
154 template <class T, size_t N, class Storage>
FastVector(std::initializer_list<value_type> init)155 FastVector<T, N, Storage>::FastVector(std::initializer_list<value_type> init)
156 {
157 assign_from_initializer_list(init);
158 }
159
160 template <class T, size_t N, class Storage>
161 template <class InputIt, std::enable_if_t<!std::is_integral<InputIt>::value, bool>>
FastVector(InputIt first,InputIt last)162 FastVector<T, N, Storage>::FastVector(InputIt first, InputIt last)
163 {
164 size_t newSize = last - first;
165 ensure_capacity(newSize);
166 mSize = newSize;
167 std::copy(first, last, begin());
168 }
169
170 template <class T, size_t N, class Storage>
171 FastVector<T, N, Storage> &FastVector<T, N, Storage>::operator=(
172 const FastVector<T, N, Storage> &other)
173 {
174 ensure_capacity(other.mSize);
175 mSize = other.mSize;
176 std::copy(other.begin(), other.end(), begin());
177 return *this;
178 }
179
180 template <class T, size_t N, class Storage>
181 FastVector<T, N, Storage> &FastVector<T, N, Storage>::operator=(FastVector<T, N, Storage> &&other)
182 {
183 swap(other);
184 return *this;
185 }
186
187 template <class T, size_t N, class Storage>
188 FastVector<T, N, Storage> &FastVector<T, N, Storage>::operator=(
189 std::initializer_list<value_type> init)
190 {
191 assign_from_initializer_list(init);
192 return *this;
193 }
194
195 template <class T, size_t N, class Storage>
~FastVector()196 FastVector<T, N, Storage>::~FastVector()
197 {
198 clear();
199 if (!uses_fixed_storage())
200 {
201 delete[] mData;
202 }
203 }
204
205 template <class T, size_t N, class Storage>
at(size_type pos)206 typename FastVector<T, N, Storage>::reference FastVector<T, N, Storage>::at(size_type pos)
207 {
208 ASSERT(pos < mSize);
209 return mData[pos];
210 }
211
212 template <class T, size_t N, class Storage>
at(size_type pos)213 typename FastVector<T, N, Storage>::const_reference FastVector<T, N, Storage>::at(
214 size_type pos) const
215 {
216 ASSERT(pos < mSize);
217 return mData[pos];
218 }
219
220 template <class T, size_t N, class Storage>
221 ANGLE_INLINE typename FastVector<T, N, Storage>::reference FastVector<T, N, Storage>::operator[](
222 size_type pos)
223 {
224 ASSERT(pos < mSize);
225 return mData[pos];
226 }
227
228 template <class T, size_t N, class Storage>
229 ANGLE_INLINE typename FastVector<T, N, Storage>::const_reference
230 FastVector<T, N, Storage>::operator[](size_type pos) const
231 {
232 ASSERT(pos < mSize);
233 return mData[pos];
234 }
235
236 template <class T, size_t N, class Storage>
237 ANGLE_INLINE typename FastVector<T, N, Storage>::const_pointer
data()238 angle::FastVector<T, N, Storage>::data() const
239 {
240 return mData;
241 }
242
243 template <class T, size_t N, class Storage>
data()244 ANGLE_INLINE typename FastVector<T, N, Storage>::pointer angle::FastVector<T, N, Storage>::data()
245 {
246 return mData;
247 }
248
249 template <class T, size_t N, class Storage>
begin()250 ANGLE_INLINE typename FastVector<T, N, Storage>::iterator FastVector<T, N, Storage>::begin()
251 {
252 return mData;
253 }
254
255 template <class T, size_t N, class Storage>
begin()256 ANGLE_INLINE typename FastVector<T, N, Storage>::const_iterator FastVector<T, N, Storage>::begin()
257 const
258 {
259 return mData;
260 }
261
262 template <class T, size_t N, class Storage>
end()263 ANGLE_INLINE typename FastVector<T, N, Storage>::iterator FastVector<T, N, Storage>::end()
264 {
265 return mData + mSize;
266 }
267
268 template <class T, size_t N, class Storage>
end()269 ANGLE_INLINE typename FastVector<T, N, Storage>::const_iterator FastVector<T, N, Storage>::end()
270 const
271 {
272 return mData + mSize;
273 }
274
275 template <class T, size_t N, class Storage>
empty()276 ANGLE_INLINE bool FastVector<T, N, Storage>::empty() const
277 {
278 return mSize == 0;
279 }
280
281 template <class T, size_t N, class Storage>
size()282 ANGLE_INLINE typename FastVector<T, N, Storage>::size_type FastVector<T, N, Storage>::size() const
283 {
284 return mSize;
285 }
286
287 template <class T, size_t N, class Storage>
clear()288 void FastVector<T, N, Storage>::clear()
289 {
290 resize(0);
291 }
292
293 template <class T, size_t N, class Storage>
push_back(const value_type & value)294 ANGLE_INLINE void FastVector<T, N, Storage>::push_back(const value_type &value)
295 {
296 if (mSize == mReservedSize)
297 ensure_capacity(mSize + 1);
298 mData[mSize++] = value;
299 }
300
301 template <class T, size_t N, class Storage>
push_back(value_type && value)302 ANGLE_INLINE void FastVector<T, N, Storage>::push_back(value_type &&value)
303 {
304 emplace_back(std::move(value));
305 }
306
307 template <class T, size_t N, class Storage>
308 template <typename... Args>
emplace_back(Args &&...args)309 ANGLE_INLINE void FastVector<T, N, Storage>::emplace_back(Args &&... args)
310 {
311 if (mSize == mReservedSize)
312 ensure_capacity(mSize + 1);
313 mData[mSize++] = std::move(T(std::forward<Args>(args)...));
314 }
315
316 template <class T, size_t N, class Storage>
pop_back()317 ANGLE_INLINE void FastVector<T, N, Storage>::pop_back()
318 {
319 ASSERT(mSize > 0);
320 mSize--;
321 }
322
323 template <class T, size_t N, class Storage>
front()324 ANGLE_INLINE typename FastVector<T, N, Storage>::reference FastVector<T, N, Storage>::front()
325 {
326 ASSERT(mSize > 0);
327 return mData[0];
328 }
329
330 template <class T, size_t N, class Storage>
front()331 ANGLE_INLINE typename FastVector<T, N, Storage>::const_reference FastVector<T, N, Storage>::front()
332 const
333 {
334 ASSERT(mSize > 0);
335 return mData[0];
336 }
337
338 template <class T, size_t N, class Storage>
back()339 ANGLE_INLINE typename FastVector<T, N, Storage>::reference FastVector<T, N, Storage>::back()
340 {
341 ASSERT(mSize > 0);
342 return mData[mSize - 1];
343 }
344
345 template <class T, size_t N, class Storage>
back()346 ANGLE_INLINE typename FastVector<T, N, Storage>::const_reference FastVector<T, N, Storage>::back()
347 const
348 {
349 ASSERT(mSize > 0);
350 return mData[mSize - 1];
351 }
352
353 template <class T, size_t N, class Storage>
swap(FastVector<T,N,Storage> & other)354 void FastVector<T, N, Storage>::swap(FastVector<T, N, Storage> &other)
355 {
356 std::swap(mSize, other.mSize);
357
358 pointer tempData = other.mData;
359 if (uses_fixed_storage())
360 other.mData = other.mFixedStorage.data();
361 else
362 other.mData = mData;
363 if (tempData == other.mFixedStorage.data())
364 mData = mFixedStorage.data();
365 else
366 mData = tempData;
367 std::swap(mReservedSize, other.mReservedSize);
368
369 if (uses_fixed_storage() || other.uses_fixed_storage())
370 std::swap(mFixedStorage, other.mFixedStorage);
371 }
372
373 template <class T, size_t N, class Storage>
resize(size_type count)374 void FastVector<T, N, Storage>::resize(size_type count)
375 {
376 if (count > mSize)
377 {
378 ensure_capacity(count);
379 }
380 mSize = count;
381 }
382
383 template <class T, size_t N, class Storage>
resize(size_type count,const value_type & value)384 void FastVector<T, N, Storage>::resize(size_type count, const value_type &value)
385 {
386 if (count > mSize)
387 {
388 ensure_capacity(count);
389 std::fill(mData + mSize, mData + count, value);
390 }
391 mSize = count;
392 }
393
394 template <class T, size_t N, class Storage>
assign_from_initializer_list(std::initializer_list<value_type> init)395 void FastVector<T, N, Storage>::assign_from_initializer_list(std::initializer_list<value_type> init)
396 {
397 ensure_capacity(init.size());
398 mSize = init.size();
399 size_t index = 0;
400 for (auto &value : init)
401 {
402 mData[index++] = value;
403 }
404 }
405
406 template <class T, size_t N, class Storage>
remove_and_permute(const value_type & element)407 ANGLE_INLINE void FastVector<T, N, Storage>::remove_and_permute(const value_type &element)
408 {
409 size_t len = mSize - 1;
410 for (size_t index = 0; index < len; ++index)
411 {
412 if (mData[index] == element)
413 {
414 mData[index] = std::move(mData[len]);
415 break;
416 }
417 }
418 pop_back();
419 }
420
421 template <class T, size_t N, class Storage>
ensure_capacity(size_t capacity)422 void FastVector<T, N, Storage>::ensure_capacity(size_t capacity)
423 {
424 // We have a minimum capacity of N.
425 if (mReservedSize < capacity)
426 {
427 ASSERT(capacity > N);
428 size_type newSize = std::max(mReservedSize, N);
429 while (newSize < capacity)
430 {
431 newSize *= 2;
432 }
433
434 pointer newData = new value_type[newSize];
435
436 if (mSize > 0)
437 {
438 std::move(begin(), end(), newData);
439 }
440
441 if (!uses_fixed_storage())
442 {
443 delete[] mData;
444 }
445
446 mData = newData;
447 mReservedSize = newSize;
448 }
449 }
450
451 template <class Value, size_t N>
452 class FastMap final
453 {
454 public:
FastMap()455 FastMap() {}
~FastMap()456 ~FastMap() {}
457
458 Value &operator[](uint32_t key)
459 {
460 if (mData.size() <= key)
461 {
462 mData.resize(key + 1, {});
463 }
464 return mData[key];
465 }
466
467 const Value &operator[](uint32_t key) const
468 {
469 ASSERT(key < mData.size());
470 return mData[key];
471 }
472
clear()473 void clear() { mData.clear(); }
474
empty()475 bool empty() const { return mData.empty(); }
size()476 size_t size() const { return mData.size(); }
477
data()478 const Value *data() const { return mData.data(); }
479
480 bool operator==(const FastMap<Value, N> &other) const
481 {
482 return (size() == other.size()) &&
483 (memcmp(data(), other.data(), size() * sizeof(Value)) == 0);
484 }
485
486 private:
487 FastVector<Value, N> mData;
488 };
489
490 template <class Key, class Value, size_t N>
491 class FlatUnorderedMap final
492 {
493 public:
494 using Pair = std::pair<Key, Value>;
495
FlatUnorderedMap()496 FlatUnorderedMap() {}
~FlatUnorderedMap()497 ~FlatUnorderedMap() {}
498
insert(Key key,Value value)499 void insert(Key key, Value value)
500 {
501 ASSERT(!contains(key));
502 mData.push_back(Pair(key, value));
503 }
504
contains(Key key)505 bool contains(Key key) const
506 {
507 for (size_t index = 0; index < mData.size(); ++index)
508 {
509 if (mData[index].first == key)
510 return true;
511 }
512 return false;
513 }
514
clear()515 void clear() { mData.clear(); }
516
get(Key key,Value * value)517 bool get(Key key, Value *value) const
518 {
519 for (size_t index = 0; index < mData.size(); ++index)
520 {
521 const Pair &item = mData[index];
522 if (item.first == key)
523 {
524 *value = item.second;
525 return true;
526 }
527 }
528 return false;
529 }
530
empty()531 bool empty() const { return mData.empty(); }
size()532 size_t size() const { return mData.size(); }
533
534 private:
535 FastVector<Pair, N> mData;
536 };
537
538 template <class T, size_t N>
539 class FlatUnorderedSet final
540 {
541 public:
FlatUnorderedSet()542 FlatUnorderedSet() {}
~FlatUnorderedSet()543 ~FlatUnorderedSet() {}
544
empty()545 bool empty() const { return mData.empty(); }
546
insert(T value)547 void insert(T value)
548 {
549 ASSERT(!contains(value));
550 mData.push_back(value);
551 }
552
contains(T needle)553 bool contains(T needle) const
554 {
555 for (T value : mData)
556 {
557 if (value == needle)
558 return true;
559 }
560 return false;
561 }
562
clear()563 void clear() { mData.clear(); }
564
565 private:
566 FastVector<T, N> mData;
567 };
568
569 class FastIntegerSet final
570 {
571 public:
572 static constexpr size_t kWindowSize = 64;
573 static constexpr size_t kOneLessThanKWindowSize = kWindowSize - 1;
574 static constexpr size_t kShiftForDivision =
575 static_cast<size_t>(rx::Log2(static_cast<unsigned int>(kWindowSize)));
576 using KeyBitSet = angle::BitSet64<kWindowSize>;
577
578 ANGLE_INLINE FastIntegerSet();
579 ANGLE_INLINE ~FastIntegerSet();
580
ensureCapacity(size_t size)581 ANGLE_INLINE void ensureCapacity(size_t size)
582 {
583 if (capacity() <= size)
584 {
585 reserve(size * 2);
586 }
587 }
588
insert(uint64_t key)589 ANGLE_INLINE void insert(uint64_t key)
590 {
591 size_t sizedKey = static_cast<size_t>(key);
592
593 ASSERT(!contains(sizedKey));
594 ensureCapacity(sizedKey);
595 ASSERT(capacity() > sizedKey);
596
597 size_t index = sizedKey >> kShiftForDivision;
598 size_t offset = sizedKey & kOneLessThanKWindowSize;
599
600 mKeyData[index].set(offset, true);
601 }
602
contains(uint64_t key)603 ANGLE_INLINE bool contains(uint64_t key) const
604 {
605 size_t sizedKey = static_cast<size_t>(key);
606
607 size_t index = sizedKey >> kShiftForDivision;
608 size_t offset = sizedKey & kOneLessThanKWindowSize;
609
610 return (sizedKey < capacity()) && (mKeyData[index].test(offset));
611 }
612
clear()613 ANGLE_INLINE void clear()
614 {
615 for (KeyBitSet &it : mKeyData)
616 {
617 it.reset();
618 }
619 }
620
empty()621 ANGLE_INLINE bool empty() const
622 {
623 for (const KeyBitSet &it : mKeyData)
624 {
625 if (it.any())
626 {
627 return false;
628 }
629 }
630 return true;
631 }
632
size()633 ANGLE_INLINE size_t size() const
634 {
635 size_t valid_entries = 0;
636 for (const KeyBitSet &it : mKeyData)
637 {
638 valid_entries += it.count();
639 }
640 return valid_entries;
641 }
642
643 private:
capacity()644 ANGLE_INLINE size_t capacity() const { return kWindowSize * mKeyData.size(); }
645
reserve(size_t newSize)646 ANGLE_INLINE void reserve(size_t newSize)
647 {
648 size_t alignedSize = rx::roundUpPow2(newSize, kWindowSize);
649 size_t count = alignedSize >> kShiftForDivision;
650
651 mKeyData.resize(count, KeyBitSet::Zero());
652 }
653
654 std::vector<KeyBitSet> mKeyData;
655 };
656
657 // This is needed to accommodate the chromium style guide error -
658 // [chromium-style] Complex constructor has an inlined body.
FastIntegerSet()659 ANGLE_INLINE FastIntegerSet::FastIntegerSet() {}
~FastIntegerSet()660 ANGLE_INLINE FastIntegerSet::~FastIntegerSet() {}
661
662 template <typename Value>
663 class FastIntegerMap final
664 {
665 public:
FastIntegerMap()666 FastIntegerMap() {}
~FastIntegerMap()667 ~FastIntegerMap() {}
668
ensureCapacity(size_t size)669 ANGLE_INLINE void ensureCapacity(size_t size)
670 {
671 // Ensure key set has capacity
672 mKeySet.ensureCapacity(size);
673
674 // Ensure value vector has capacity
675 ensureCapacityImpl(size);
676 }
677
insert(uint64_t key,Value value)678 ANGLE_INLINE void insert(uint64_t key, Value value)
679 {
680 // Insert key
681 ASSERT(!mKeySet.contains(key));
682 mKeySet.insert(key);
683
684 // Insert value
685 size_t sizedKey = static_cast<size_t>(key);
686 ensureCapacityImpl(sizedKey);
687 ASSERT(capacity() > sizedKey);
688 mValueData[sizedKey] = value;
689 }
690
contains(uint64_t key)691 ANGLE_INLINE bool contains(uint64_t key) const { return mKeySet.contains(key); }
692
get(uint64_t key,Value * out)693 ANGLE_INLINE bool get(uint64_t key, Value *out) const
694 {
695 if (!mKeySet.contains(key))
696 {
697 return false;
698 }
699
700 size_t sizedKey = static_cast<size_t>(key);
701 *out = mValueData[sizedKey];
702 return true;
703 }
704
clear()705 ANGLE_INLINE void clear() { mKeySet.clear(); }
706
empty()707 ANGLE_INLINE bool empty() const { return mKeySet.empty(); }
708
size()709 ANGLE_INLINE size_t size() const { return mKeySet.size(); }
710
711 private:
capacity()712 ANGLE_INLINE size_t capacity() const { return mValueData.size(); }
713
ensureCapacityImpl(size_t size)714 ANGLE_INLINE void ensureCapacityImpl(size_t size)
715 {
716 if (capacity() <= size)
717 {
718 reserve(size * 2);
719 }
720 }
721
reserve(size_t newSize)722 ANGLE_INLINE void reserve(size_t newSize)
723 {
724 size_t alignedSize = rx::roundUpPow2(newSize, FastIntegerSet::kWindowSize);
725 mValueData.resize(alignedSize);
726 }
727
728 FastIntegerSet mKeySet;
729 std::vector<Value> mValueData;
730 };
731 } // namespace angle
732
733 #endif // COMMON_FASTVECTOR_H_
734