Commit 86d9c93a by Shahbaz Youssefi Committed by Commit Bot

Use TSpan for TType's array sizes

Until C++20, std::vector doesn't have a constexpr constructor, which means TType cannot use a `TVector` for `mArraySizes` if an arrayed type needs to be created constexpr. This is needed for the upcoming textureGatherOffsets implementation. A new TSpan class is introduced, based on std::span (from C++20) that holds the pointer/size allocated from a TVector without owning it. Since TVector's allocation are made from a pool, the allocated memory will live beyond the vector's destruction. `TType::mArraySizes` is changed to this type. This change will allow a new constexpr constructor to be added to TType that takes a TSpan as array directly, a value which is constexpr initialized from a static array (instead of TVector). Bug: angleproject:3569 Change-Id: I78793b0f4c64519e0ebe30cf6e0de995ba70035d Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1968260Reviewed-by: 's avatarJiajia Qin <jiajia.qin@intel.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent c713abfd
......@@ -653,9 +653,10 @@ void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,
variableOut->fields.push_back(fieldVariable);
}
}
if (auto *arraySizes = type.getArraySizes())
const TSpan<const unsigned int> &arraySizes = type.getArraySizes();
if (!arraySizes.empty())
{
variableOut->arraySizes.assign(arraySizes->begin(), arraySizes->end());
variableOut->arraySizes.assign(arraySizes.begin(), arraySizes.end());
}
}
......
......@@ -108,6 +108,105 @@ class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D>>>
{}
};
// Basic implementation of C++20's span for use with pool-allocated containers (TVector) or static
// arrays. This is used by the array sizes member of TType to allow arrayed types to be
// constexpr-constructed.
// See the reference for std::span here: https://en.cppreference.com/w/cpp/container/span
template <typename T>
class TSpan
{
public:
typedef size_t size_type;
constexpr TSpan() {}
constexpr TSpan(T *ptr, size_type size) : mData(ptr), mSize(size) {}
constexpr TSpan(const TSpan &that) : mData(that.mData), mSize(that.mSize) {}
constexpr TSpan &operator=(const TSpan &that)
{
mData = that.mData;
mSize = that.mSize;
return *this;
}
// Note: the pointer is taken out of the TVector because TVector's memory is pool allocated,
// so the memory will live on even if the TVector is destroyed.
template <typename S>
TSpan(const TVector<S> &vec) : mData(vec.data()), mSize(vec.size())
{}
template <typename S>
TSpan &operator=(const TVector<S> &vec)
{
mData = vec.data();
mSize = vec.size();
return *this;
}
constexpr bool operator==(const TSpan &that) const
{
if (mSize != that.mSize)
{
return false;
}
if (mData == that.mData)
{
return true;
}
for (size_type index = 0; index < mSize; ++index)
{
if (mData[index] != that.mData[index])
{
return false;
}
}
return true;
}
constexpr bool operator!=(const TSpan &that) const { return !(*this == that); }
constexpr T *data() const { return mData; }
constexpr size_type size() const { return mSize; }
constexpr bool empty() const { return mSize == 0; }
constexpr T &operator[](size_type index) const { return mData[index]; }
constexpr T &front() const { return mData[0]; }
constexpr T &back() const { return mData[mSize - 1]; }
constexpr T *begin() const { return mData; }
constexpr T *end() const { return mData + mSize; }
constexpr std::reverse_iterator<T *> rbegin() const
{
return std::make_reverse_iterator(end());
}
constexpr std::reverse_iterator<T *> rend() const
{
return std::make_reverse_iterator(begin());
}
constexpr TSpan first(size_type count) const
{
ASSERT(count <= mSize);
return count == 0 ? TSpan() : TSpan(mData, count);
}
constexpr TSpan last(size_type count) const
{
ASSERT(count <= mSize);
return count == 0 ? TSpan() : TSpan(mData + mSize - count, count);
}
constexpr TSpan subspan(size_type offset, size_type count) const
{
ASSERT(offset + count <= mSize);
return count == 0 ? TSpan() : TSpan(mData + offset, count);
}
private:
T *mData = nullptr;
size_t mSize = 0;
};
// Integer to TString conversion
template <typename T>
inline TString str(T i)
......
......@@ -73,8 +73,8 @@ TInfoSinkBase &TInfoSinkBase::operator<<(const TType &type)
if (type.isArray())
{
for (auto arraySizeIter = type.getArraySizes()->rbegin();
arraySizeIter != type.getArraySizes()->rend(); ++arraySizeIter)
for (auto arraySizeIter = type.getArraySizes().rbegin();
arraySizeIter != type.getArraySizes().rend(); ++arraySizeIter)
{
*this << "array[" << (*arraySizeIter) << "] of ";
}
......
......@@ -43,7 +43,7 @@ TString ArrayHelperFunctionName(const char *prefix, const TType &type)
fnName << prefix << "_";
if (type.isArray())
{
for (unsigned int arraySize : *type.getArraySizes())
for (unsigned int arraySize : type.getArraySizes())
{
fnName << arraySize << "_";
}
......
......@@ -1961,8 +1961,7 @@ bool TParseContext::executeInitializer(const TSourceLoc &line,
// will default to setting array sizes to 1. We have not checked yet whether the initializer
// actually is an array or not. Having a non-array initializer for an unsized array will
// result in an error later, so we don't generate an error message here.
auto *arraySizes = initializer->getType().getArraySizes();
type->sizeUnsizedArrays(arraySizes);
type->sizeUnsizedArrays(initializer->getType().getArraySizes());
}
const TQualifier qualifier = type->getQualifier();
......@@ -3531,7 +3530,7 @@ void TParseContext::checkIsNotUnsizedArray(const TSourceLoc &line,
if (arrayType->isUnsizedArray())
{
error(line, errorMessage, token);
arrayType->sizeUnsizedArrays(nullptr);
arrayType->sizeUnsizedArrays(TSpan<const unsigned int>());
}
}
......@@ -3623,7 +3622,7 @@ TIntermTyped *TParseContext::addConstructor(TFunctionLookup *fnCall, const TSour
{
if (!checkUnsizedArrayConstructorArgumentDimensionality(arguments, type, line))
{
type.sizeUnsizedArrays(nullptr);
type.sizeUnsizedArrays(TSpan<const unsigned int>());
return CreateZeroNode(type);
}
TIntermTyped *firstElement = arguments.at(0)->getAsTyped();
......@@ -3634,9 +3633,9 @@ TIntermTyped *TParseContext::addConstructor(TFunctionLookup *fnCall, const TSour
}
for (size_t i = 0; i < firstElement->getType().getNumArraySizes(); ++i)
{
if ((*type.getArraySizes())[i] == 0u)
if (type.getArraySizes()[i] == 0u)
{
type.setArraySize(i, (*firstElement->getType().getArraySizes())[i]);
type.setArraySize(i, firstElement->getType().getArraySizes()[i]);
}
}
ASSERT(!type.isUnsizedArray());
......@@ -5227,7 +5226,7 @@ bool TParseContext::binaryOpCommonCheck(TOperator op,
return false;
}
// At this point, size of implicitly sized arrays should be resolved.
if (*left->getType().getArraySizes() != *right->getType().getArraySizes())
if (left->getType().getArraySizes() != right->getType().getArraySizes())
{
error(loc, "array size mismatch", GetOperatorString(op));
return false;
......
......@@ -111,10 +111,10 @@ const BlockMemberInfo GetBlockMemberInfoByType(const TType &type,
}
std::vector<unsigned int> arraySizes;
auto *typeArraySizes = type.getArraySizes();
if (typeArraySizes != nullptr)
const TSpan<const unsigned int> &typeArraySizes = type.getArraySizes();
if (!typeArraySizes.empty())
{
arraySizes.assign(typeArraySizes->begin(), typeArraySizes->end());
arraySizes.assign(typeArraySizes.begin(), typeArraySizes.end());
}
return encoder->encodeType(GLVariableType(type), arraySizes, rowMajor);
}
......@@ -677,7 +677,7 @@ void ShaderStorageBlockOutputHLSL::writeEOpIndexDirectOrIndirectOutput(TInfoSink
{
if (type.isArrayOfArrays())
{
const TVector<unsigned int> &arraySizes = *type.getArraySizes();
const TSpan<const unsigned int> &arraySizes = type.getArraySizes();
// Don't need to concern the tail comma which will be used to multiply the index.
for (unsigned int i = 0; i < (arraySizes.size() - 1); i++)
{
......
......@@ -143,7 +143,7 @@ TType::TType(const TPublicType &p)
layoutQualifier(p.layoutQualifier),
primarySize(p.getPrimarySize()),
secondarySize(p.getSecondarySize()),
mArraySizes(nullptr),
mArraySizesStorage(nullptr),
mInterfaceBlock(nullptr),
mStructure(nullptr),
mIsStructSpecifier(false),
......@@ -153,7 +153,7 @@ TType::TType(const TPublicType &p)
ASSERT(secondarySize <= 4);
if (p.isArray())
{
mArraySizes = new TVector<unsigned int>(*p.arraySizes);
makeArrays(*p.arraySizes);
}
if (p.getUserDef())
{
......@@ -194,11 +194,24 @@ TType &TType::operator=(const TType &t)
layoutQualifier = t.layoutQualifier;
primarySize = t.primarySize;
secondarySize = t.secondarySize;
mArraySizes = t.mArraySizes ? new TVector<unsigned int>(*t.mArraySizes) : nullptr;
mArraySizesStorage = nullptr;
mInterfaceBlock = t.mInterfaceBlock;
mStructure = t.mStructure;
mIsStructSpecifier = t.mIsStructSpecifier;
mMangledName = t.mMangledName;
if (t.mArraySizesStorage)
{
// If other type has storage, duplicate the storage and set the view to our own storage.
mArraySizesStorage = new TVector<unsigned int>(*t.mArraySizesStorage);
mArraySizes = *mArraySizesStorage;
}
else
{
// Otherwise reference the same (constexpr) array sizes as the other type.
mArraySizes = t.mArraySizes;
}
return *this;
}
......@@ -425,16 +438,13 @@ const char *TType::buildMangledName() const
}
}
if (mArraySizes)
for (unsigned int arraySize : mArraySizes)
{
for (unsigned int arraySize : *mArraySizes)
{
char buf[20];
snprintf(buf, sizeof(buf), "%d", arraySize);
mangledName += '[';
mangledName += buf;
mangledName += ']';
}
char buf[20];
snprintf(buf, sizeof(buf), "%d", arraySize);
mangledName += '[';
mangledName += buf;
mangledName += ']';
}
// Copy string contents into a pool-allocated buffer, so we never need to call delete.
......@@ -453,15 +463,12 @@ size_t TType::getObjectSize() const
if (totalSize == 0)
return 0;
if (mArraySizes)
for (size_t arraySize : mArraySizes)
{
for (size_t arraySize : *mArraySizes)
{
if (arraySize > INT_MAX / totalSize)
totalSize = INT_MAX;
else
totalSize *= arraySize;
}
if (arraySize > INT_MAX / totalSize)
totalSize = INT_MAX;
else
totalSize *= arraySize;
}
return totalSize;
......@@ -481,18 +488,15 @@ int TType::getLocationCount() const
return 0;
}
if (mArraySizes)
for (unsigned int arraySize : mArraySizes)
{
for (unsigned int arraySize : *mArraySizes)
if (arraySize > static_cast<unsigned int>(std::numeric_limits<int>::max() / count))
{
if (arraySize > static_cast<unsigned int>(std::numeric_limits<int>::max() / count))
{
count = std::numeric_limits<int>::max();
}
else
{
count *= static_cast<int>(arraySize);
}
count = std::numeric_limits<int>::max();
}
else
{
count *= static_cast<int>(arraySize);
}
}
......@@ -501,12 +505,9 @@ int TType::getLocationCount() const
unsigned int TType::getArraySizeProduct() const
{
if (!mArraySizes)
return 1u;
unsigned int product = 1u;
for (unsigned int arraySize : *mArraySizes)
for (unsigned int arraySize : mArraySizes)
{
product *= arraySize;
}
......@@ -515,10 +516,7 @@ unsigned int TType::getArraySizeProduct() const
bool TType::isUnsizedArray() const
{
if (!mArraySizes)
return false;
for (unsigned int arraySize : *mArraySizes)
for (unsigned int arraySize : mArraySizes)
{
if (arraySize == 0u)
{
......@@ -544,34 +542,30 @@ bool TType::isElementTypeOf(const TType &arrayType) const
{
return false;
}
if (isArray())
for (size_t i = 0; i < mArraySizes.size(); ++i)
{
for (size_t i = 0; i < mArraySizes->size(); ++i)
if (mArraySizes[i] != arrayType.mArraySizes[i])
{
if ((*mArraySizes)[i] != (*arrayType.mArraySizes)[i])
{
return false;
}
return false;
}
}
return true;
}
void TType::sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes)
void TType::sizeUnsizedArrays(const TSpan<const unsigned int> &newArraySizes)
{
size_t newArraySizesSize = newArraySizes ? newArraySizes->size() : 0;
ASSERT(!isArray() || mArraySizesStorage != nullptr);
for (size_t i = 0u; i < getNumArraySizes(); ++i)
{
if ((*mArraySizes)[i] == 0)
if (mArraySizes[i] == 0)
{
if (i < newArraySizesSize)
if (i < newArraySizes.size())
{
ASSERT(newArraySizes != nullptr);
(*mArraySizes)[i] = (*newArraySizes)[i];
(*mArraySizesStorage)[i] = newArraySizes[i];
}
else
{
(*mArraySizes)[i] = 1u;
(*mArraySizesStorage)[i] = 1u;
}
}
}
......@@ -580,9 +574,9 @@ void TType::sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes)
void TType::sizeOutermostUnsizedArray(unsigned int arraySize)
{
ASSERT(isArray());
ASSERT(mArraySizes->back() == 0u);
mArraySizes->back() = arraySize;
ASSERT(isArray() && mArraySizesStorage != nullptr);
ASSERT((*mArraySizesStorage).back() == 0u);
(*mArraySizesStorage).back() = arraySize;
}
void TType::setBasicType(TBasicType t)
......@@ -616,54 +610,61 @@ void TType::setSecondarySize(unsigned char ss)
void TType::makeArray(unsigned int s)
{
if (!mArraySizes)
mArraySizes = new TVector<unsigned int>();
mArraySizes->push_back(s);
invalidateMangledName();
if (mArraySizesStorage == nullptr)
{
mArraySizesStorage = new TVector<unsigned int>();
}
// Add a dimension to the current ones.
mArraySizesStorage->push_back(s);
onArrayDimensionsChange(*mArraySizesStorage);
}
void TType::makeArrays(const TVector<unsigned int> &sizes)
void TType::makeArrays(const TSpan<const unsigned int> &sizes)
{
if (!mArraySizes)
mArraySizes = new TVector<unsigned int>();
if (mArraySizesStorage == nullptr)
{
mArraySizesStorage = new TVector<unsigned int>();
}
// Add dimensions to the current ones.
mArraySizesStorage->insert(mArraySizesStorage->end(), sizes.begin(), sizes.end());
onArrayDimensionsChange(*mArraySizesStorage);
}
mArraySizes->insert(mArraySizes->end(), sizes.begin(), sizes.end());
void TType::onArrayDimensionsChange(const TSpan<const unsigned int> &sizes)
{
mArraySizes = sizes;
invalidateMangledName();
}
void TType::setArraySize(size_t arrayDimension, unsigned int s)
{
ASSERT(mArraySizes != nullptr);
ASSERT(arrayDimension < mArraySizes->size());
if (mArraySizes->at(arrayDimension) != s)
ASSERT(isArray() && mArraySizesStorage != nullptr);
ASSERT(arrayDimension < mArraySizesStorage->size());
if (mArraySizes[arrayDimension] != s)
{
(*mArraySizes)[arrayDimension] = s;
(*mArraySizesStorage)[arrayDimension] = s;
invalidateMangledName();
}
}
void TType::toArrayElementType()
{
ASSERT(mArraySizes != nullptr);
if (mArraySizes->size() > 0)
{
mArraySizes->pop_back();
invalidateMangledName();
}
ASSERT(isArray() && mArraySizesStorage != nullptr);
mArraySizesStorage->pop_back();
onArrayDimensionsChange(*mArraySizesStorage);
}
void TType::toArrayBaseType()
{
if (mArraySizes == nullptr)
if (!isArray())
{
return;
}
if (mArraySizes->size() > 0)
if (mArraySizesStorage)
{
mArraySizes->clear();
mArraySizesStorage->clear();
}
invalidateMangledName();
onArrayDimensionsChange(TSpan<const unsigned int>());
}
void TType::setInterfaceBlock(const TInterfaceBlock *interfaceBlockIn)
......
......@@ -122,7 +122,7 @@ class TType
layoutQualifier(TLayoutQualifier::Create()),
primarySize(ps),
secondarySize(ss),
mArraySizes(nullptr),
mArraySizesStorage(nullptr),
mInterfaceBlock(nullptr),
mStructure(nullptr),
mIsStructSpecifier(false),
......@@ -140,11 +140,14 @@ class TType
primarySize(t.primarySize),
secondarySize(t.secondarySize),
mArraySizes(t.mArraySizes),
mArraySizesStorage(t.mArraySizesStorage),
mInterfaceBlock(t.mInterfaceBlock),
mStructure(t.mStructure),
mIsStructSpecifier(t.mIsStructSpecifier),
mMangledName(t.mMangledName)
{}
{
t.mArraySizesStorage = nullptr;
}
constexpr TBasicType getBasicType() const { return type; }
void setBasicType(TBasicType t);
......@@ -190,28 +193,28 @@ class TType
bool isMatrix() const { return primarySize > 1 && secondarySize > 1; }
bool isNonSquareMatrix() const { return isMatrix() && primarySize != secondarySize; }
bool isArray() const { return mArraySizes != nullptr && !mArraySizes->empty(); }
bool isArrayOfArrays() const { return isArray() && mArraySizes->size() > 1u; }
size_t getNumArraySizes() const { return isArray() ? mArraySizes->size() : 0; }
const TVector<unsigned int> *getArraySizes() const { return mArraySizes; }
bool isArray() const { return !mArraySizes.empty(); }
bool isArrayOfArrays() const { return mArraySizes.size() > 1u; }
size_t getNumArraySizes() const { return mArraySizes.size(); }
const TSpan<const unsigned int> &getArraySizes() const { return mArraySizes; }
unsigned int getArraySizeProduct() const;
bool isUnsizedArray() const;
unsigned int getOutermostArraySize() const
{
ASSERT(isArray());
return mArraySizes->back();
return mArraySizes.back();
}
void makeArray(unsigned int s);
// sizes contain new outermost array sizes.
void makeArrays(const TVector<unsigned int> &sizes);
void makeArrays(const TSpan<const unsigned int> &sizes);
// Here, the array dimension value 0 corresponds to the innermost array.
void setArraySize(size_t arrayDimension, unsigned int s);
// Will set unsized array sizes according to newArraySizes. In case there are more
// unsized arrays than there are sizes in newArraySizes, defaults to setting any
// remaining array sizes to 1.
void sizeUnsizedArrays(const TVector<unsigned int> *newArraySizes);
void sizeUnsizedArrays(const TSpan<const unsigned int> &newArraySizes);
// Will size the outermost array according to arraySize.
void sizeOutermostUnsizedArray(unsigned int arraySize);
......@@ -258,7 +261,7 @@ class TType
size_t numArraySizesL = getNumArraySizes();
size_t numArraySizesR = right.getNumArraySizes();
bool arraySizesEqual = numArraySizesL == numArraySizesR &&
(numArraySizesL == 0 || *mArraySizes == *right.mArraySizes);
(numArraySizesL == 0 || mArraySizes == right.mArraySizes);
return type == right.type && primarySize == right.primarySize &&
secondarySize == right.secondarySize && arraySizesEqual &&
mStructure == right.mStructure;
......@@ -279,8 +282,8 @@ class TType
return numArraySizesL < numArraySizesR;
for (size_t i = 0; i < numArraySizesL; ++i)
{
if ((*mArraySizes)[i] != (*right.mArraySizes)[i])
return (*mArraySizes)[i] < (*right.mArraySizes)[i];
if (mArraySizes[i] != right.mArraySizes[i])
return mArraySizes[i] < right.mArraySizes[i];
}
if (mStructure != right.mStructure)
return mStructure < right.mStructure;
......@@ -342,12 +345,14 @@ class TType
private:
void invalidateMangledName();
const char *buildMangledName() const;
void onArrayDimensionsChange(const TSpan<const unsigned int> &sizes);
TBasicType type;
TPrecision precision;
TQualifier qualifier;
bool invariant;
bool precise;
TMemoryQualifier memoryQualifier;
TLayoutQualifier layoutQualifier;
unsigned char primarySize; // size of vector or cols matrix
......@@ -355,7 +360,12 @@ class TType
// Used to make an array type. Outermost array size is stored at the end of the vector. Having 0
// in this vector means an unsized array.
TVector<unsigned int> *mArraySizes;
TSpan<const unsigned int> mArraySizes;
// Storage for mArraySizes, if any. This is usually the case, except for constexpr TTypes which
// only have a valid mArraySizes (with mArraySizesStorage being nullptr). Therefore, all
// modifications to array sizes happen on the storage (and if dimensions change, mArraySizes is
// also updated) and all reads are from mArraySizes.
TVector<unsigned int> *mArraySizesStorage;
// This is set only in the following two cases:
// 1) Represents an interface block.
......
//
// Copyright 2019 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.
//
// span_unittests.cpp: Unit tests for the TSpan class.
//
#include "Common.h"
#include <gtest/gtest.h>
using namespace angle;
namespace
{
using Span = sh::TSpan<const unsigned int>;
constexpr size_t kSpanDataSize = 16;
constexpr unsigned int kSpanData[kSpanDataSize] = {0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15};
// Test that comparing spans work
TEST(SpanTest, Comparison)
{
// Duplicate data to make sure comparison is being done on values (and not addresses).
constexpr unsigned int kSpanDataDup[kSpanDataSize] = {0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15};
// Don't use ASSERT_EQ at first because the == is more hidden
ASSERT_TRUE(Span() == Span(kSpanData, 0));
ASSERT_TRUE(Span(kSpanData + 3, 4) != Span(kSpanDataDup + 5, 4));
// Check ASSERT_EQ and ASSERT_NE work correctly
ASSERT_EQ(Span(kSpanData, kSpanDataSize), Span(kSpanDataDup, kSpanDataSize));
ASSERT_NE(Span(kSpanData, kSpanDataSize - 1), Span(kSpanDataDup + 1, kSpanDataSize - 1));
ASSERT_NE(Span(kSpanData, kSpanDataSize), Span(kSpanDataDup, kSpanDataSize - 1));
ASSERT_NE(Span(kSpanData, kSpanDataSize - 1), Span(kSpanDataDup, kSpanDataSize));
ASSERT_NE(Span(kSpanData, 0), Span(kSpanDataDup, 1));
ASSERT_NE(Span(kSpanData, 1), Span(kSpanDataDup, 0));
}
// Test indexing
TEST(SpanTest, Indexing)
{
constexpr Span sp(kSpanData, kSpanDataSize);
for (size_t i = 0; i < kSpanDataSize; ++i)
{
ASSERT_EQ(sp[i], i);
}
unsigned int storage[kSpanDataSize] = {};
sh::TSpan<unsigned int> writableSpan(storage, kSpanDataSize);
for (size_t i = 0; i < kSpanDataSize; ++i)
{
writableSpan[i] = i;
}
for (size_t i = 0; i < kSpanDataSize; ++i)
{
ASSERT_EQ(writableSpan[i], i);
}
for (size_t i = 0; i < kSpanDataSize; ++i)
{
ASSERT_EQ(storage[i], i);
}
}
// Test for the various constructors
TEST(SpanTest, Constructors)
{
// Default constructor
{
Span sp;
ASSERT_TRUE(sp.size() == 0);
ASSERT_TRUE(sp.empty());
}
// Constexpr construct from pointer
{
constexpr Span sp(kSpanData, kSpanDataSize);
ASSERT_EQ(sp.data(), kSpanData);
ASSERT_EQ(sp.size(), kSpanDataSize);
ASSERT_FALSE(sp.empty());
}
// Copy constructor and copy assignment
{
Span sp(kSpanData, kSpanDataSize);
Span sp2(sp);
Span sp3;
ASSERT_EQ(sp, sp2);
ASSERT_EQ(sp2.data(), kSpanData);
ASSERT_EQ(sp2.size(), kSpanDataSize);
ASSERT_FALSE(sp2.empty());
sp3 = sp;
ASSERT_EQ(sp, sp3);
ASSERT_EQ(sp3.data(), kSpanData);
ASSERT_EQ(sp3.size(), kSpanDataSize);
ASSERT_FALSE(sp3.empty());
}
}
// Test accessing the data directly
TEST(SpanTest, DataAccess)
{
constexpr Span sp(kSpanData, kSpanDataSize);
const unsigned int *data = sp.data();
for (size_t i = 0; i < kSpanDataSize; ++i)
{
ASSERT_EQ(data[i], i);
}
}
// Test front and back
TEST(SpanTest, FrontAndBack)
{
constexpr Span sp(kSpanData, kSpanDataSize);
ASSERT_TRUE(sp.front() == 0);
ASSERT_EQ(sp.back(), kSpanDataSize - 1);
}
// Test begin and end
TEST(SpanTest, BeginAndEnd)
{
constexpr Span sp(kSpanData, kSpanDataSize);
size_t currentIndex = 0;
for (unsigned int value : sp)
{
ASSERT_EQ(value, currentIndex);
++currentIndex;
}
}
// Test reverse begin and end
TEST(SpanTest, RbeginAndRend)
{
constexpr Span sp(kSpanData, kSpanDataSize);
size_t currentIndex = 0;
for (auto iter = sp.rbegin(); iter != sp.rend(); ++iter)
{
ASSERT_EQ(*iter, kSpanDataSize - 1 - currentIndex);
++currentIndex;
}
}
// Test first and last
TEST(SpanTest, FirstAndLast)
{
constexpr Span sp(kSpanData, kSpanDataSize);
constexpr size_t kSplitSize = kSpanDataSize / 4;
constexpr Span first = sp.first(kSplitSize);
constexpr Span last = sp.last(kSplitSize);
ASSERT_EQ(first, Span(kSpanData, kSplitSize));
ASSERT_EQ(first.data(), kSpanData);
ASSERT_EQ(first.size(), kSplitSize);
ASSERT_EQ(last, Span(kSpanData + kSpanDataSize - kSplitSize, kSplitSize));
ASSERT_EQ(last.data(), kSpanData + kSpanDataSize - kSplitSize);
ASSERT_EQ(last.size(), kSplitSize);
}
// Test subspan
TEST(SpanTest, Subspan)
{
constexpr Span sp(kSpanData, kSpanDataSize);
constexpr size_t kSplitOffset = kSpanDataSize / 4;
constexpr size_t kSplitSize = kSpanDataSize / 2;
constexpr Span subspan = sp.subspan(kSplitOffset, kSplitSize);
ASSERT_EQ(subspan, Span(kSpanData + kSplitOffset, kSplitSize));
ASSERT_EQ(subspan.data(), kSpanData + kSplitOffset);
ASSERT_EQ(subspan.size(), kSplitSize);
}
} // anonymous namespace
......@@ -513,18 +513,18 @@ class RewriteAtomicCountersTraverser : public TIntermTraverser
TIntermSymbol *argumentAsSymbol = symbol->getAsSymbolNode();
ASSERT(argumentAsSymbol);
const TVector<unsigned int> *arraySizes = argumentAsSymbol->getType().getArraySizes();
const TSpan<const unsigned int> &arraySizes = argumentAsSymbol->getType().getArraySizes();
// Calculate Pi
TVector<unsigned int> runningArraySizeProducts;
if (arraySizes && arraySizes->size() > 0)
if (!arraySizes.empty())
{
runningArraySizeProducts.resize(arraySizes->size());
runningArraySizeProducts.resize(arraySizes.size());
uint32_t runningProduct = 1;
for (size_t dimension = 0; dimension < arraySizes->size(); ++dimension)
for (size_t dimension = 0; dimension < arraySizes.size(); ++dimension)
{
runningArraySizeProducts[dimension] = runningProduct;
runningProduct *= (*arraySizes)[dimension];
runningProduct *= arraySizes[dimension];
}
}
......
......@@ -78,7 +78,7 @@ void CopyArraySizes(const TType *from, TType *to)
{
if (from->isArray())
{
to->makeArrays(*from->getArraySizes());
to->makeArrays(from->getArraySizes());
}
}
......@@ -219,15 +219,15 @@ class TransformArrayHelper
TransformArrayHelper(TIntermTyped *baseExpression)
: mBaseExpression(baseExpression),
mBaseExpressionType(baseExpression->getType()),
mArrayIndices(mBaseExpressionType.getArraySizes()->size(), 0)
mArrayIndices(mBaseExpressionType.getArraySizes().size(), 0)
{}
TIntermTyped *getNextElement(TIntermTyped *valueExpression, TIntermTyped **valueElementOut)
{
const TVector<unsigned int> *arraySizes = mBaseExpressionType.getArraySizes();
const TSpan<const unsigned int> &arraySizes = mBaseExpressionType.getArraySizes();
// If the last index overflows, element enumeration is done.
if (mArrayIndices.back() >= arraySizes->back())
if (mArrayIndices.back() >= arraySizes.back())
{
return nullptr;
}
......@@ -252,7 +252,8 @@ class TransformArrayHelper
TIntermTyped *constructReadTransformExpression()
{
const TVector<unsigned int> &arraySizes = *mBaseExpressionType.getArraySizes();
const TSpan<const unsigned int> &baseTypeArraySizes = mBaseExpressionType.getArraySizes();
TVector<unsigned int> arraySizes(baseTypeArraySizes.begin(), baseTypeArraySizes.end());
TIntermTyped *firstElement = mReadTransformConstructorArgs.front()->getAsTyped();
const TType &baseType = firstElement->getType();
......@@ -282,19 +283,19 @@ class TransformArrayHelper
return element;
}
void incrementIndices(const TVector<unsigned int> *arraySizes)
void incrementIndices(const TSpan<const unsigned int> &arraySizes)
{
// Assume mArrayIndices is an N digit number, where digit i is in the range
// [0, arraySizes[i]). This function increments this number. Last digit is the most
// significant digit.
for (size_t digitIndex = 0; digitIndex < arraySizes->size(); ++digitIndex)
for (size_t digitIndex = 0; digitIndex < arraySizes.size(); ++digitIndex)
{
++mArrayIndices[digitIndex];
if (mArrayIndices[digitIndex] < (*arraySizes)[digitIndex])
if (mArrayIndices[digitIndex] < arraySizes[digitIndex])
{
break;
}
if (digitIndex + 1 != arraySizes->size())
if (digitIndex + 1 != arraySizes.size())
{
// This digit has now overflown and is reset to 0, carry will be added to the next
// digit. The most significant digit will keep the overflow though, to make it
......@@ -305,8 +306,8 @@ class TransformArrayHelper
}
TIntermTyped *constructReadTransformExpressionHelper(
const TVector<unsigned int> arraySizes,
const TVector<unsigned int> accumulatedArraySizes,
const TVector<unsigned int> &arraySizes,
const TVector<unsigned int> &accumulatedArraySizes,
const TType &baseType,
size_t elementsOffset)
{
......
......@@ -29,7 +29,7 @@ TType *GetStructSamplerParameterType(TSymbolTable *symbolTable, const TVariable
if (param.getType().isArray())
{
structType->makeArrays(*param.getType().getArraySizes());
structType->makeArrays(param.getType().getArraySizes());
}
ASSERT(!structType->isStructureContainingSamplers());
......@@ -210,7 +210,7 @@ TFunction *GenerateFunctionFromArguments(const TFunction *function,
if (type.isArray() && type.isSampler())
{
ASSERT(type.getNumArraySizes() == 1);
instantiation.push_back((*type.getArraySizes())[0]);
instantiation.push_back(type.getArraySizes()[0]);
}
}
......@@ -267,8 +267,8 @@ class ArrayTraverser
{
if (!arrayType.isArray())
return;
size_t currentArraySize = mCumulativeArraySizeStack.back();
const auto &arraySizes = *arrayType.getArraySizes();
size_t currentArraySize = mCumulativeArraySizeStack.back();
const TSpan<const unsigned int> &arraySizes = arrayType.getArraySizes();
for (auto it = arraySizes.rbegin(); it != arraySizes.rend(); ++it)
{
unsigned int arraySize = *it;
......@@ -552,7 +552,7 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser
newType = new TType(fieldStruct, true);
if (fieldType.isArray())
{
newType->makeArrays(*fieldType.getArraySizes());
newType->makeArrays(fieldType.getArraySizes());
}
}
else
......@@ -759,9 +759,9 @@ class Traverser final : public TIntermTraverser, public ArrayTraverser
// Also includes samplers in arrays of arrays.
virtual void visitSamplerInStructParam(const ImmutableString &name,
const TType *type,
size_t paramIndex) = 0;
virtual void visitStructParam(const TFunction *function, size_t paramIndex) = 0;
virtual void visitNonStructParam(const TFunction *function, size_t paramIndex) = 0;
size_t paramIndex) = 0;
virtual void visitStructParam(const TFunction *function, size_t paramIndex) = 0;
virtual void visitNonStructParam(const TFunction *function, size_t paramIndex) = 0;
private:
bool traverseStructContainingSamplers(const ImmutableString &baseName,
......
......@@ -27,7 +27,7 @@ TType *GetStructSamplerParameterType(TSymbolTable *symbolTable, const TVariable
if (param.getType().isArray())
{
structType->makeArrays(*param.getType().getArraySizes());
structType->makeArrays(param.getType().getArraySizes());
}
ASSERT(!structType->isStructureContainingSamplers());
......@@ -290,7 +290,7 @@ class Traverser final : public TIntermTraverser
newType = new TType(fieldStruct, true);
if (fieldType.isArray())
{
newType->makeArrays(*fieldType.getArraySizes());
newType->makeArrays(fieldType.getArraySizes());
}
}
else
......@@ -372,7 +372,7 @@ class Traverser final : public TIntermTraverser
size_t nonSamplerCount = 0;
// Name the samplers internally as varName_<index>_fieldName
const TVector<unsigned int> &arraySizes = *containingType.getArraySizes();
const TSpan<const unsigned int> &arraySizes = containingType.getArraySizes();
for (unsigned int arrayElement = 0; arrayElement < arraySizes[0]; ++arrayElement)
{
ImmutableStringBuilder stringBuilder(prefix.length() + kHexSize + 1);
......@@ -530,7 +530,7 @@ class Traverser final : public TIntermTraverser
if (baseType.isArray())
{
const TVector<unsigned int> &arraySizes = *baseType.getArraySizes();
const TSpan<const unsigned int> &arraySizes = baseType.getArraySizes();
ASSERT(arraySizes.size() == 1);
for (unsigned int arrayIndex = 0; arrayIndex < arraySizes[0]; ++arrayIndex)
......
......@@ -488,7 +488,7 @@ ImmutableString ArrayString(const TType &type)
if (!type.isArray())
return ImmutableString("");
const TVector<unsigned int> &arraySizes = *type.getArraySizes();
const TSpan<const unsigned int> &arraySizes = type.getArraySizes();
constexpr const size_t kMaxDecimalDigitsPerSize = 10u;
ImmutableStringBuilder arrayString(arraySizes.size() * (kMaxDecimalDigitsPerSize + 2u));
for (auto arraySizeIter = arraySizes.rbegin(); arraySizeIter != arraySizes.rend();
......
......@@ -45,6 +45,7 @@ angle_unittests_sources = [
"../libANGLE/renderer/TextureImpl_mock.h",
"../libANGLE/renderer/TransformFeedbackImpl_mock.h",
"../libANGLE/renderer/serial_utils_unittest.cpp",
"../compiler/translator/span_unittest.cpp",
"angle_unittests_utils.h",
"compiler_tests/API_test.cpp",
"compiler_tests/AppendixALimitations_test.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