// // 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 "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); 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); 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) { ensure_capacity(other.mSize); mSize = other.mSize; std::copy(other.begin(), other.end(), begin()); } template FastVector::FastVector(FastVector &&other) : FastVector() { swap(other); } template FastVector::FastVector(std::initializer_list init) { assign_from_initializer_list(init); } 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) { if (mSize == mReservedSize) ensure_capacity(mSize + 1); mData[mSize++] = std::move(value); } 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; } } } // namespace angle #endif // COMMON_FASTVECTOR_H_