• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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