Commit 2231b4e0 by Geoff Lang Committed by Commit Bot

Add a FixedVector class to have "variable" size vectors on the stack.

Wraps a std::array and a size parameter to give the std::vector interface without making allocations. BUG=angleproject:2435 Change-Id: I7df0be1310446a2f163766149bf631a8692be9ad Reviewed-on: https://chromium-review.googlesource.com/981267 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 13e31bb0
//
// 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;
size_type max_size() const;
void clear();
void push_back(const value_type &value);
void push_back(value_type &&value);
void swap(FixedVector<T, N, Storage> &other);
void resize(size_type count);
void resize(size_type count, const value_type &value);
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>
typename FixedVector<T, N, Storage>::size_type FixedVector<T, N, Storage>::max_size() const
{
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 + 1 < 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 + 1 < N);
mStorage[mSize] = std::move(value);
mSize++;
}
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)
{
resize(count, value_type());
}
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] = T();
}
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++;
}
}
} // namespace angle
#endif // COMMON_FIXEDVECTOR_H_
//
// 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_unittest:
// Tests of the FixedVector class
//
#include <gtest/gtest.h>
#include "common/FixedVector.h"
namespace angle
{
// Make sure the various constructors compile and do basic checks
TEST(FixedVector, Constructors)
{
FixedVector<int, 5> defaultContructor;
EXPECT_EQ(0u, defaultContructor.size());
FixedVector<int, 5> count(3);
EXPECT_EQ(3u, count.size());
FixedVector<int, 5> countAndValue(3, 2);
EXPECT_EQ(3u, countAndValue.size());
EXPECT_EQ(2, countAndValue[1]);
FixedVector<int, 5> copy(countAndValue);
EXPECT_EQ(copy, countAndValue);
FixedVector<int, 5> copyRValue(std::move(count));
EXPECT_EQ(3u, copyRValue.size());
FixedVector<int, 5> initializerList{1, 2, 3, 4, 5};
EXPECT_EQ(5u, initializerList.size());
EXPECT_EQ(3, initializerList[2]);
FixedVector<int, 5> assignCopy(copyRValue);
EXPECT_EQ(3u, assignCopy.size());
FixedVector<int, 5> assignRValue(std::move(assignCopy));
EXPECT_EQ(3u, assignRValue.size());
FixedVector<int, 5> assignmentInitializerList = {1, 2, 3, 4, 5};
EXPECT_EQ(5u, assignmentInitializerList.size());
EXPECT_EQ(3, assignmentInitializerList[2]);
}
// Test indexing operations (at, operator[])
TEST(FixedVector, Indexing)
{
FixedVector<int, 5> vec = {0, 1, 2, 3, 4};
EXPECT_EQ(0, vec.at(0));
EXPECT_EQ(vec[0], vec.at(0));
}
// Test the push_back functions
TEST(FixedVector, PushBack)
{
FixedVector<int, 5> vec;
vec.push_back(1);
EXPECT_EQ(1, vec[0]);
}
// Test the sizing operations
TEST(FixedVector, Size)
{
FixedVector<int, 5> vec;
EXPECT_TRUE(vec.empty());
EXPECT_EQ(0u, vec.size());
EXPECT_EQ(5u, vec.max_size());
vec.push_back(1);
EXPECT_FALSE(vec.empty());
EXPECT_EQ(1u, vec.size());
}
// Test clearing the vector
TEST(FixedVector, Clear)
{
FixedVector<int, 5> vec = {0, 1, 2, 3, 4};
vec.clear();
EXPECT_TRUE(vec.empty());
}
// Test resizing the vector
TEST(FixedVector, Resize)
{
FixedVector<int, 5> vec;
vec.resize(5u, 1);
EXPECT_EQ(5u, vec.size());
EXPECT_EQ(1, vec[4]);
vec.resize(2u);
EXPECT_EQ(2u, vec.size());
}
// Test iterating over the vector
TEST(FixedVector, Iteration)
{
FixedVector<int, 5> vec = { 0, 1, 2, 3 };
int vistedCount = 0;
for (int value : vec)
{
EXPECT_EQ(vistedCount, value);
vistedCount++;
}
EXPECT_EQ(4, vistedCount);
}
} // namespace angle
......@@ -8,6 +8,7 @@
#include "libANGLE/renderer/gl/BlitGL.h"
#include "common/FixedVector.h"
#include "common/utilities.h"
#include "common/vector_utils.h"
#include "image_util/copyimage.h"
......@@ -143,9 +144,11 @@ gl::Error SetClearState(StateManagerGL *stateManager,
return gl::NoError();
}
using ClearBindTargetVector = angle::FixedVector<GLenum, 3>;
gl::Error PrepareForClear(StateManagerGL *stateManager,
GLenum sizedInternalFormat,
std::vector<GLenum> *outBindtargets,
ClearBindTargetVector *outBindtargets,
GLbitfield *outClearMask)
{
const gl::InternalFormat &internalFormatInfo =
......@@ -175,7 +178,7 @@ gl::Error PrepareForClear(StateManagerGL *stateManager,
void UnbindAttachments(const FunctionsGL *functions,
GLenum framebufferTarget,
const std::vector<GLenum> &bindTargets)
const ClearBindTargetVector &bindTargets)
{
for (GLenum bindTarget : bindTargets)
{
......@@ -729,7 +732,7 @@ gl::ErrorOrResult<bool> BlitGL::clearRenderableTexture(TextureGL *source,
{
ANGLE_TRY(initializeResources());
std::vector<GLenum> bindTargets;
ClearBindTargetVector bindTargets;
GLbitfield clearMask = 0;
ANGLE_TRY(PrepareForClear(mStateManager, sizedInternalFormat, &bindTargets, &clearMask));
......@@ -821,7 +824,7 @@ gl::Error BlitGL::clearRenderbuffer(RenderbufferGL *source, GLenum sizedInternal
{
ANGLE_TRY(initializeResources());
std::vector<GLenum> bindTargets;
ClearBindTargetVector bindTargets;
GLbitfield clearMask = 0;
ANGLE_TRY(PrepareForClear(mStateManager, sizedInternalFormat, &bindTargets, &clearMask));
......
......@@ -10,6 +10,7 @@
[
'common/Color.h',
'common/Color.inl',
'common/FixedVector.h',
'common/Float16ToFloat32.cpp',
'common/MemoryBuffer.cpp',
'common/MemoryBuffer.h',
......
......@@ -14,6 +14,7 @@
{
'angle_unittests_sources':
[
'<(angle_path)/src/common/FixedVector_unittest.cpp',
'<(angle_path)/src/common/Optional_unittest.cpp',
'<(angle_path)/src/common/aligned_memory_unittest.cpp',
'<(angle_path)/src/common/angleutils_unittest.cpp',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment