diff options
Diffstat (limited to 'gfx/angle/checkout/src/common/FastVector.h')
-rw-r--r-- | gfx/angle/checkout/src/common/FastVector.h | 684 |
1 files changed, 684 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/common/FastVector.h b/gfx/angle/checkout/src/common/FastVector.h new file mode 100644 index 0000000000..8555af276d --- /dev/null +++ b/gfx/angle/checkout/src/common/FastVector.h @@ -0,0 +1,684 @@ +// +// 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 <algorithm> +#include <array> +#include <initializer_list> + +namespace angle +{ +template <class T, size_t N, class Storage = std::array<T, N>> +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<T, N, Storage> &other); + FastVector(FastVector<T, N, Storage> &&other); + FastVector(std::initializer_list<value_type> init); + + FastVector<T, N, Storage> &operator=(const FastVector<T, N, Storage> &other); + FastVector<T, N, Storage> &operator=(FastVector<T, N, Storage> &&other); + FastVector<T, N, Storage> &operator=(std::initializer_list<value_type> 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 <typename... Args> + void emplace_back(Args &&... args); + + void pop_back(); + + reference front(); + const_reference front() const; + + reference back(); + const_reference back() const; + + void swap(FastVector<T, N, Storage> &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<value_type> 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 <class T, size_t N, class StorageN, size_t M, class StorageM> +bool operator==(const FastVector<T, N, StorageN> &a, const FastVector<T, M, StorageM> &b) +{ + return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); +} + +template <class T, size_t N, class StorageN, size_t M, class StorageM> +bool operator!=(const FastVector<T, N, StorageN> &a, const FastVector<T, M, StorageM> &b) +{ + return !(a == b); +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE bool FastVector<T, N, Storage>::uses_fixed_storage() const +{ + return mData == mFixedStorage.data(); +} + +template <class T, size_t N, class Storage> +FastVector<T, N, Storage>::FastVector() +{} + +template <class T, size_t N, class Storage> +FastVector<T, N, Storage>::FastVector(size_type count, const value_type &value) +{ + ensure_capacity(count); + mSize = count; + std::fill(begin(), end(), value); +} + +template <class T, size_t N, class Storage> +FastVector<T, N, Storage>::FastVector(size_type count) +{ + ensure_capacity(count); + mSize = count; +} + +template <class T, size_t N, class Storage> +FastVector<T, N, Storage>::FastVector(const FastVector<T, N, Storage> &other) +{ + ensure_capacity(other.mSize); + mSize = other.mSize; + std::copy(other.begin(), other.end(), begin()); +} + +template <class T, size_t N, class Storage> +FastVector<T, N, Storage>::FastVector(FastVector<T, N, Storage> &&other) : FastVector() +{ + swap(other); +} + +template <class T, size_t N, class Storage> +FastVector<T, N, Storage>::FastVector(std::initializer_list<value_type> init) +{ + assign_from_initializer_list(init); +} + +template <class T, size_t N, class Storage> +FastVector<T, N, Storage> &FastVector<T, N, Storage>::operator=( + const FastVector<T, N, Storage> &other) +{ + ensure_capacity(other.mSize); + mSize = other.mSize; + std::copy(other.begin(), other.end(), begin()); + return *this; +} + +template <class T, size_t N, class Storage> +FastVector<T, N, Storage> &FastVector<T, N, Storage>::operator=(FastVector<T, N, Storage> &&other) +{ + swap(*this, other); + return *this; +} + +template <class T, size_t N, class Storage> +FastVector<T, N, Storage> &FastVector<T, N, Storage>::operator=( + std::initializer_list<value_type> init) +{ + assign_from_initializer_list(init); + return *this; +} + +template <class T, size_t N, class Storage> +FastVector<T, N, Storage>::~FastVector() +{ + clear(); + if (!uses_fixed_storage()) + { + delete[] mData; + } +} + +template <class T, size_t N, class Storage> +typename FastVector<T, N, Storage>::reference FastVector<T, N, Storage>::at(size_type pos) +{ + ASSERT(pos < mSize); + return mData[pos]; +} + +template <class T, size_t N, class Storage> +typename FastVector<T, N, Storage>::const_reference FastVector<T, N, Storage>::at( + size_type pos) const +{ + ASSERT(pos < mSize); + return mData[pos]; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::reference FastVector<T, N, Storage>::operator[]( + size_type pos) +{ + ASSERT(pos < mSize); + return mData[pos]; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::const_reference +FastVector<T, N, Storage>::operator[](size_type pos) const +{ + ASSERT(pos < mSize); + return mData[pos]; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::const_pointer +angle::FastVector<T, N, Storage>::data() const +{ + return mData; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::pointer angle::FastVector<T, N, Storage>::data() +{ + return mData; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::iterator FastVector<T, N, Storage>::begin() +{ + return mData; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::const_iterator FastVector<T, N, Storage>::begin() + const +{ + return mData; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::iterator FastVector<T, N, Storage>::end() +{ + return mData + mSize; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::const_iterator FastVector<T, N, Storage>::end() + const +{ + return mData + mSize; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE bool FastVector<T, N, Storage>::empty() const +{ + return mSize == 0; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::size_type FastVector<T, N, Storage>::size() const +{ + return mSize; +} + +template <class T, size_t N, class Storage> +void FastVector<T, N, Storage>::clear() +{ + resize(0); +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE void FastVector<T, N, Storage>::push_back(const value_type &value) +{ + if (mSize == mReservedSize) + ensure_capacity(mSize + 1); + mData[mSize++] = value; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE void FastVector<T, N, Storage>::push_back(value_type &&value) +{ + emplace_back(std::move(value)); +} + +template <class T, size_t N, class Storage> +template <typename... Args> +ANGLE_INLINE void FastVector<T, N, Storage>::emplace_back(Args &&... args) +{ + if (mSize == mReservedSize) + ensure_capacity(mSize + 1); + mData[mSize++] = std::move(T(std::forward<Args>(args)...)); +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE void FastVector<T, N, Storage>::pop_back() +{ + ASSERT(mSize > 0); + mSize--; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::reference FastVector<T, N, Storage>::front() +{ + ASSERT(mSize > 0); + return mData[0]; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::const_reference FastVector<T, N, Storage>::front() + const +{ + ASSERT(mSize > 0); + return mData[0]; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::reference FastVector<T, N, Storage>::back() +{ + ASSERT(mSize > 0); + return mData[mSize - 1]; +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE typename FastVector<T, N, Storage>::const_reference FastVector<T, N, Storage>::back() + const +{ + ASSERT(mSize > 0); + return mData[mSize - 1]; +} + +template <class T, size_t N, class Storage> +void FastVector<T, N, Storage>::swap(FastVector<T, N, Storage> &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 <class T, size_t N, class Storage> +void FastVector<T, N, Storage>::resize(size_type count) +{ + if (count > mSize) + { + ensure_capacity(count); + } + mSize = count; +} + +template <class T, size_t N, class Storage> +void FastVector<T, N, Storage>::resize(size_type count, const value_type &value) +{ + if (count > mSize) + { + ensure_capacity(count); + std::fill(mData + mSize, mData + count, value); + } + mSize = count; +} + +template <class T, size_t N, class Storage> +void FastVector<T, N, Storage>::assign_from_initializer_list(std::initializer_list<value_type> init) +{ + ensure_capacity(init.size()); + mSize = init.size(); + size_t index = 0; + for (auto &value : init) + { + mData[index++] = value; + } +} + +template <class T, size_t N, class Storage> +ANGLE_INLINE void FastVector<T, N, Storage>::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 <class T, size_t N, class Storage> +void FastVector<T, N, Storage>::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 Key, class Value, size_t N> +class FastUnorderedMap final +{ + public: + using Pair = std::pair<Key, Value>; + + 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<Pair, N> mData; +}; + +template <class T, size_t N> +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<T, N> 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<size_t>(rx::Log2(static_cast<unsigned int>(kWindowSize))); + using KeyBitSet = angle::BitSet64<kWindowSize>; + + 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<size_t>(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<size_t>(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<KeyBitSet> 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 <typename Value> +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<size_t>(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<size_t>(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<Value> mValueData; +}; +} // namespace angle + +#endif // COMMON_FASTVECTOR_H_ |