| // | |
| // 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. | |
| // | |
| // FixedVector.h: | |
| // A vector class with a maximum size and fixed storage. | |
| // | |
| #ifndef COMMON_FIXEDVECTOR_H_ | |
| #define COMMON_FIXEDVECTOR_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 FixedVector 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 = typename Storage::iterator; | |
| using const_iterator = typename Storage::const_iterator; | |
| using reverse_iterator = typename Storage::reverse_iterator; | |
| using const_reverse_iterator = typename Storage::const_reverse_iterator; | |
| FixedVector(); | |
| FixedVector(size_type count, const value_type &value); | |
| FixedVector(size_type count); | |
| FixedVector(const FixedVector<T, N, Storage> &other); | |
| FixedVector(FixedVector<T, N, Storage> &&other); | |
| FixedVector(std::initializer_list<value_type> init); | |
| FixedVector<T, N, Storage> &operator=(const FixedVector<T, N, Storage> &other); | |
| FixedVector<T, N, Storage> &operator=(FixedVector<T, N, Storage> &&other); | |
| FixedVector<T, N, Storage> &operator=(std::initializer_list<value_type> init); | |
| ~FixedVector(); | |
| 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; | |
| static constexpr size_type max_size(); | |
| void clear(); | |
| void push_back(const value_type &value); | |
| void push_back(value_type &&value); | |
| template <class... Args> | |
| void emplace_back(Args &&... args); | |
| void pop_back(); | |
| reference back(); | |
| const_reference back() const; | |
| void swap(FixedVector<T, N, Storage> &other); | |
| void resize(size_type count); | |
| void resize(size_type count, const value_type &value); | |
| bool full() const; | |
| private: | |
| void assign_from_initializer_list(std::initializer_list<value_type> init); | |
| Storage mStorage; | |
| size_type mSize = 0; | |
| }; | |
| template <class T, size_t N, class Storage> | |
| bool operator==(const FixedVector<T, N, Storage> &a, const FixedVector<T, N, Storage> &b) | |
| { | |
| return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); | |
| } | |
| template <class T, size_t N, class Storage> | |
| bool operator!=(const FixedVector<T, N, Storage> &a, const FixedVector<T, N, Storage> &b) | |
| { | |
| return !(a == b); | |
| } | |
| template <class T, size_t N, class Storage> | |
| FixedVector<T, N, Storage>::FixedVector() = default; | |
| template <class T, size_t N, class Storage> | |
| FixedVector<T, N, Storage>::FixedVector(size_type count, const value_type &value) : mSize(count) | |
| { | |
| ASSERT(count <= N); | |
| std::fill(mStorage.begin(), mStorage.begin() + count, value); | |
| } | |
| template <class T, size_t N, class Storage> | |
| FixedVector<T, N, Storage>::FixedVector(size_type count) : mSize(count) | |
| { | |
| ASSERT(count <= N); | |
| } | |
| template <class T, size_t N, class Storage> | |
| FixedVector<T, N, Storage>::FixedVector(const FixedVector<T, N, Storage> &other) = default; | |
| template <class T, size_t N, class Storage> | |
| FixedVector<T, N, Storage>::FixedVector(FixedVector<T, N, Storage> &&other) = default; | |
| template <class T, size_t N, class Storage> | |
| FixedVector<T, N, Storage>::FixedVector(std::initializer_list<value_type> init) | |
| { | |
| ASSERT(init.size() <= N); | |
| assign_from_initializer_list(init); | |
| } | |
| template <class T, size_t N, class Storage> | |
| FixedVector<T, N, Storage> &FixedVector<T, N, Storage>::operator=( | |
| const FixedVector<T, N, Storage> &other) = default; | |
| template <class T, size_t N, class Storage> | |
| FixedVector<T, N, Storage> &FixedVector<T, N, Storage>::operator=( | |
| FixedVector<T, N, Storage> &&other) = default; | |
| template <class T, size_t N, class Storage> | |
| FixedVector<T, N, Storage> &FixedVector<T, N, Storage>::operator=( | |
| std::initializer_list<value_type> init) | |
| { | |
| clear(); | |
| ASSERT(init.size() <= N); | |
| assign_from_initializer_list(init); | |
| return this; | |
| } | |
| template <class T, size_t N, class Storage> | |
| FixedVector<T, N, Storage>::~FixedVector() | |
| { | |
| clear(); | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::reference FixedVector<T, N, Storage>::at(size_type pos) | |
| { | |
| ASSERT(pos < N); | |
| return mStorage.at(pos); | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::const_reference FixedVector<T, N, Storage>::at( | |
| size_type pos) const | |
| { | |
| ASSERT(pos < N); | |
| return mStorage.at(pos); | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::reference FixedVector<T, N, Storage>::operator[](size_type pos) | |
| { | |
| ASSERT(pos < N); | |
| return mStorage[pos]; | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::const_reference FixedVector<T, N, Storage>::operator[]( | |
| size_type pos) const | |
| { | |
| ASSERT(pos < N); | |
| return mStorage[pos]; | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::const_pointer angle::FixedVector<T, N, Storage>::data() const | |
| { | |
| return mStorage.data(); | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::pointer angle::FixedVector<T, N, Storage>::data() | |
| { | |
| return mStorage.data(); | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::iterator FixedVector<T, N, Storage>::begin() | |
| { | |
| return mStorage.begin(); | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::const_iterator FixedVector<T, N, Storage>::begin() const | |
| { | |
| return mStorage.begin(); | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::iterator FixedVector<T, N, Storage>::end() | |
| { | |
| return mStorage.begin() + mSize; | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::const_iterator FixedVector<T, N, Storage>::end() const | |
| { | |
| return mStorage.begin() + mSize; | |
| } | |
| template <class T, size_t N, class Storage> | |
| bool FixedVector<T, N, Storage>::empty() const | |
| { | |
| return mSize == 0; | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::size_type FixedVector<T, N, Storage>::size() const | |
| { | |
| return mSize; | |
| } | |
| template <class T, size_t N, class Storage> | |
| constexpr typename FixedVector<T, N, Storage>::size_type FixedVector<T, N, Storage>::max_size() | |
| { | |
| return N; | |
| } | |
| template <class T, size_t N, class Storage> | |
| void FixedVector<T, N, Storage>::clear() | |
| { | |
| resize(0); | |
| } | |
| template <class T, size_t N, class Storage> | |
| void FixedVector<T, N, Storage>::push_back(const value_type &value) | |
| { | |
| ASSERT(mSize < N); | |
| mStorage[mSize] = value; | |
| mSize++; | |
| } | |
| template <class T, size_t N, class Storage> | |
| void FixedVector<T, N, Storage>::push_back(value_type &&value) | |
| { | |
| ASSERT(mSize < N); | |
| mStorage[mSize] = std::move(value); | |
| mSize++; | |
| } | |
| template <class T, size_t N, class Storage> | |
| template <class... Args> | |
| void FixedVector<T, N, Storage>::emplace_back(Args &&... args) | |
| { | |
| ASSERT(mSize < N); | |
| new (&mStorage[mSize]) T{std::forward<Args>(args)...}; | |
| mSize++; | |
| } | |
| template <class T, size_t N, class Storage> | |
| void FixedVector<T, N, Storage>::pop_back() | |
| { | |
| ASSERT(mSize > 0); | |
| mSize--; | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::reference FixedVector<T, N, Storage>::back() | |
| { | |
| ASSERT(mSize > 0); | |
| return mStorage[mSize - 1]; | |
| } | |
| template <class T, size_t N, class Storage> | |
| typename FixedVector<T, N, Storage>::const_reference FixedVector<T, N, Storage>::back() const | |
| { | |
| ASSERT(mSize > 0); | |
| return mStorage[mSize - 1]; | |
| } | |
| template <class T, size_t N, class Storage> | |
| void FixedVector<T, N, Storage>::swap(FixedVector<T, N, Storage> &other) | |
| { | |
| std::swap(mSize, other.mSize); | |
| std::swap(mStorage, other.mStorage); | |
| } | |
| template <class T, size_t N, class Storage> | |
| void FixedVector<T, N, Storage>::resize(size_type count) | |
| { | |
| ASSERT(count <= N); | |
| while (mSize > count) | |
| { | |
| mSize--; | |
| mStorage[mSize] = value_type(); | |
| } | |
| while (mSize < count) | |
| { | |
| mStorage[mSize] = value_type(); | |
| mSize++; | |
| } | |
| } | |
| template <class T, size_t N, class Storage> | |
| void FixedVector<T, N, Storage>::resize(size_type count, const value_type &value) | |
| { | |
| ASSERT(count <= N); | |
| while (mSize > count) | |
| { | |
| mSize--; | |
| mStorage[mSize] = value_type(); | |
| } | |
| while (mSize < count) | |
| { | |
| mStorage[mSize] = value; | |
| mSize++; | |
| } | |
| } | |
| template <class T, size_t N, class Storage> | |
| void FixedVector<T, N, Storage>::assign_from_initializer_list( | |
| std::initializer_list<value_type> init) | |
| { | |
| for (auto element : init) | |
| { | |
| mStorage[mSize] = std::move(element); | |
| mSize++; | |
| } | |
| } | |
| template <class T, size_t N, class Storage> | |
| bool FixedVector<T, N, Storage>::full() const | |
| { | |
| return (mSize == N); | |
| } | |
| } // namespace angle | |
| #endif // COMMON_FIXEDVECTOR_H_ |