// // Copyright 2018 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // FastVector.h: // A vector class with a initial fixed size and variable growth. // Based on FixedVector. // #ifndef COMMON_FASTVECTOR_H_ #define COMMON_FASTVECTOR_H_ #include "bitset_utils.h" #include "common/debug.h" #include #include #include namespace angle { template > class FastVector final { public: using value_type = typename Storage::value_type; using size_type = typename Storage::size_type; using reference = typename Storage::reference; using const_reference = typename Storage::const_reference; using pointer = typename Storage::pointer; using const_pointer = typename Storage::const_pointer; using iterator = T *; using const_iterator = const T *; FastVector(); FastVector(size_type count, const value_type &value); FastVector(size_type count); FastVector(const FastVector &other); FastVector(FastVector &&other); FastVector(std::initializer_list init); template ::value, bool> = true> FastVector(InputIt first, InputIt last); FastVector &operator=(const FastVector &other); FastVector &operator=(FastVector &&other); FastVector &operator=(std::initializer_list init); ~FastVector(); reference at(size_type pos); const_reference at(size_type pos) const; reference operator[](size_type pos); const_reference operator[](size_type pos) const; pointer data(); const_pointer data() const; iterator begin(); const_iterator begin() const; iterator end(); const_iterator end() const; bool empty() const; size_type size() const; void clear(); void push_back(const value_type &value); void push_back(value_type &&value); template void emplace_back(Args &&... args); void pop_back(); reference front(); const_reference front() const; reference back(); const_reference back() const; void swap(FastVector &other); void resize(size_type count); void resize(size_type count, const value_type &value); // Specialty function that removes a known element and might shuffle the list. void remove_and_permute(const value_type &element); private: void assign_from_initializer_list(std::initializer_list init); void ensure_capacity(size_t capacity); bool uses_fixed_storage() const; Storage mFixedStorage; pointer mData = mFixedStorage.data(); size_type mSize = 0; size_type mReservedSize = N; }; template bool operator==(const FastVector &a, const FastVector &b) { return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); } template bool operator!=(const FastVector &a, const FastVector &b) { return !(a == b); } template ANGLE_INLINE bool FastVector::uses_fixed_storage() const { return mData == mFixedStorage.data(); } template FastVector::FastVector() {} template FastVector::FastVector(size_type count, const value_type &value) { ensure_capacity(count); mSize = count; std::fill(begin(), end(), value); } template FastVector::FastVector(size_type count) { ensure_capacity(count); mSize = count; } template FastVector::FastVector(const FastVector &other) : FastVector(other.begin(), other.end()) {} template FastVector::FastVector(FastVector &&other) : FastVector() { swap(other); } template FastVector::FastVector(std::initializer_list init) { assign_from_initializer_list(init); } template template ::value, bool>> FastVector::FastVector(InputIt first, InputIt last) { mSize = last - first; ensure_capacity(mSize); std::copy(first, last, begin()); } template FastVector &FastVector::operator=( const FastVector &other) { ensure_capacity(other.mSize); mSize = other.mSize; std::copy(other.begin(), other.end(), begin()); return *this; } template FastVector &FastVector::operator=(FastVector &&other) { swap(*this, other); return *this; } template FastVector &FastVector::operator=( std::initializer_list init) { assign_from_initializer_list(init); return *this; } template FastVector::~FastVector() { clear(); if (!uses_fixed_storage()) { delete[] mData; } } template typename FastVector::reference FastVector::at(size_type pos) { ASSERT(pos < mSize); return mData[pos]; } template typename FastVector::const_reference FastVector::at( size_type pos) const { ASSERT(pos < mSize); return mData[pos]; } template ANGLE_INLINE typename FastVector::reference FastVector::operator[]( size_type pos) { ASSERT(pos < mSize); return mData[pos]; } template ANGLE_INLINE typename FastVector::const_reference FastVector::operator[](size_type pos) const { ASSERT(pos < mSize); return mData[pos]; } template ANGLE_INLINE typename FastVector::const_pointer angle::FastVector::data() const { return mData; } template ANGLE_INLINE typename FastVector::pointer angle::FastVector::data() { return mData; } template ANGLE_INLINE typename FastVector::iterator FastVector::begin() { return mData; } template ANGLE_INLINE typename FastVector::const_iterator FastVector::begin() const { return mData; } template ANGLE_INLINE typename FastVector::iterator FastVector::end() { return mData + mSize; } template ANGLE_INLINE typename FastVector::const_iterator FastVector::end() const { return mData + mSize; } template ANGLE_INLINE bool FastVector::empty() const { return mSize == 0; } template ANGLE_INLINE typename FastVector::size_type FastVector::size() const { return mSize; } template void FastVector::clear() { resize(0); } template ANGLE_INLINE void FastVector::push_back(const value_type &value) { if (mSize == mReservedSize) ensure_capacity(mSize + 1); mData[mSize++] = value; } template ANGLE_INLINE void FastVector::push_back(value_type &&value) { emplace_back(std::move(value)); } template template ANGLE_INLINE void FastVector::emplace_back(Args &&... args) { if (mSize == mReservedSize) ensure_capacity(mSize + 1); mData[mSize++] = std::move(T(std::forward(args)...)); } template ANGLE_INLINE void FastVector::pop_back() { ASSERT(mSize > 0); mSize--; } template ANGLE_INLINE typename FastVector::reference FastVector::front() { ASSERT(mSize > 0); return mData[0]; } template ANGLE_INLINE typename FastVector::const_reference FastVector::front() const { ASSERT(mSize > 0); return mData[0]; } template ANGLE_INLINE typename FastVector::reference FastVector::back() { ASSERT(mSize > 0); return mData[mSize - 1]; } template ANGLE_INLINE typename FastVector::const_reference FastVector::back() const { ASSERT(mSize > 0); return mData[mSize - 1]; } template void FastVector::swap(FastVector &other) { std::swap(mSize, other.mSize); pointer tempData = other.mData; if (uses_fixed_storage()) other.mData = other.mFixedStorage.data(); else other.mData = mData; if (tempData == other.mFixedStorage.data()) mData = mFixedStorage.data(); else mData = tempData; std::swap(mReservedSize, other.mReservedSize); if (uses_fixed_storage() || other.uses_fixed_storage()) std::swap(mFixedStorage, other.mFixedStorage); } template void FastVector::resize(size_type count) { if (count > mSize) { ensure_capacity(count); } mSize = count; } template void FastVector::resize(size_type count, const value_type &value) { if (count > mSize) { ensure_capacity(count); std::fill(mData + mSize, mData + count, value); } mSize = count; } template void FastVector::assign_from_initializer_list(std::initializer_list init) { ensure_capacity(init.size()); mSize = init.size(); size_t index = 0; for (auto &value : init) { mData[index++] = value; } } template ANGLE_INLINE void FastVector::remove_and_permute(const value_type &element) { size_t len = mSize - 1; for (size_t index = 0; index < len; ++index) { if (mData[index] == element) { mData[index] = std::move(mData[len]); break; } } pop_back(); } template void FastVector::ensure_capacity(size_t capacity) { // We have a minimum capacity of N. if (mReservedSize < capacity) { ASSERT(capacity > N); size_type newSize = std::max(mReservedSize, N); while (newSize < capacity) { newSize *= 2; } pointer newData = new value_type[newSize]; if (mSize > 0) { std::move(begin(), end(), newData); } if (!uses_fixed_storage()) { delete[] mData; } mData = newData; mReservedSize = newSize; } } template class FastUnorderedMap final { public: using Pair = std::pair; FastUnorderedMap() {} ~FastUnorderedMap() {} void insert(Key key, Value value) { ASSERT(!contains(key)); mData.push_back(Pair(key, value)); } bool contains(Key key) const { for (size_t index = 0; index < mData.size(); ++index) { if (mData[index].first == key) return true; } return false; } void clear() { mData.clear(); } bool get(Key key, Value *value) const { for (size_t index = 0; index < mData.size(); ++index) { const Pair &item = mData[index]; if (item.first == key) { *value = item.second; return true; } } return false; } bool empty() const { return mData.empty(); } size_t size() const { return mData.size(); } private: FastVector mData; }; template class FastUnorderedSet final { public: FastUnorderedSet() {} ~FastUnorderedSet() {} bool empty() const { return mData.empty(); } void insert(T value) { ASSERT(!contains(value)); mData.push_back(value); } bool contains(T needle) const { for (T value : mData) { if (value == needle) return true; } return false; } void clear() { mData.clear(); } private: FastVector mData; }; class FastIntegerSet final { public: static constexpr size_t kWindowSize = 64; static constexpr size_t kOneLessThanKWindowSize = kWindowSize - 1; static constexpr size_t kShiftForDivision = static_cast(rx::Log2(static_cast(kWindowSize))); using KeyBitSet = angle::BitSet64; ANGLE_INLINE FastIntegerSet(); ANGLE_INLINE ~FastIntegerSet(); ANGLE_INLINE void ensureCapacity(size_t size) { if (capacity() <= size) { reserve(size * 2); } } ANGLE_INLINE void insert(uint64_t key) { size_t sizedKey = static_cast(key); ASSERT(!contains(sizedKey)); ensureCapacity(sizedKey); ASSERT(capacity() > sizedKey); size_t index = sizedKey >> kShiftForDivision; size_t offset = sizedKey & kOneLessThanKWindowSize; mKeyData[index].set(offset, true); } ANGLE_INLINE bool contains(uint64_t key) const { size_t sizedKey = static_cast(key); size_t index = sizedKey >> kShiftForDivision; size_t offset = sizedKey & kOneLessThanKWindowSize; return (sizedKey < capacity()) && (mKeyData[index].test(offset)); } ANGLE_INLINE void clear() { for (KeyBitSet &it : mKeyData) { it.reset(); } } ANGLE_INLINE bool empty() const { for (const KeyBitSet &it : mKeyData) { if (it.any()) { return false; } } return true; } ANGLE_INLINE size_t size() const { size_t valid_entries = 0; for (const KeyBitSet &it : mKeyData) { valid_entries += it.count(); } return valid_entries; } private: ANGLE_INLINE size_t capacity() const { return kWindowSize * mKeyData.size(); } ANGLE_INLINE void reserve(size_t newSize) { size_t alignedSize = rx::roundUpPow2(newSize, kWindowSize); size_t count = alignedSize >> kShiftForDivision; mKeyData.resize(count, KeyBitSet::Zero()); } std::vector mKeyData; }; // This is needed to accommodate the chromium style guide error - // [chromium-style] Complex constructor has an inlined body. ANGLE_INLINE FastIntegerSet::FastIntegerSet() {} ANGLE_INLINE FastIntegerSet::~FastIntegerSet() {} template class FastIntegerMap final { public: FastIntegerMap() {} ~FastIntegerMap() {} ANGLE_INLINE void ensureCapacity(size_t size) { // Ensure key set has capacity mKeySet.ensureCapacity(size); // Ensure value vector has capacity ensureCapacityImpl(size); } ANGLE_INLINE void insert(uint64_t key, Value value) { // Insert key ASSERT(!mKeySet.contains(key)); mKeySet.insert(key); // Insert value size_t sizedKey = static_cast(key); ensureCapacityImpl(sizedKey); ASSERT(capacity() > sizedKey); mValueData[sizedKey] = value; } ANGLE_INLINE bool contains(uint64_t key) const { return mKeySet.contains(key); } ANGLE_INLINE bool get(uint64_t key, Value *out) const { if (!mKeySet.contains(key)) { return false; } size_t sizedKey = static_cast(key); *out = mValueData[sizedKey]; return true; } ANGLE_INLINE void clear() { mKeySet.clear(); } ANGLE_INLINE bool empty() const { return mKeySet.empty(); } ANGLE_INLINE size_t size() const { return mKeySet.size(); } private: ANGLE_INLINE size_t capacity() const { return mValueData.size(); } ANGLE_INLINE void ensureCapacityImpl(size_t size) { if (capacity() <= size) { reserve(size * 2); } } ANGLE_INLINE void reserve(size_t newSize) { size_t alignedSize = rx::roundUpPow2(newSize, FastIntegerSet::kWindowSize); mValueData.resize(alignedSize); } FastIntegerSet mKeySet; std::vector mValueData; }; } // namespace angle #endif // COMMON_FASTVECTOR_H_