mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-06 13:15:59 +00:00
tint: Replace VectorRef with ConstVectorRef.
The elements of the VectorRef is now immutable, but can be moved, if the caller relinquishes ownership by explicitly using std::move() at the callsite. Also add utils::Empty as a way of signalling that a vector should be constructed with no elements. This is helpful in templated code where {} cannot be used due to overload ambiguity. Change-Id: I24a50a13956b0692771a8bc9046336ad46261562 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/97842 Reviewed-by: Dan Sinclair <dsinclair@chromium.org> Commit-Queue: Ben Clayton <bclayton@google.com> Auto-Submit: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
bdc619f5ef
commit
34d46731bb
@ -2082,7 +2082,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverTest,
|
|||||||
testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
|
testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
|
||||||
|
|
||||||
static std::string to_str(const std::string& function,
|
static std::string to_str(const std::string& function,
|
||||||
utils::ConstVectorRef<const sem::Parameter*> params) {
|
utils::VectorRef<const sem::Parameter*> params) {
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
out << function << "(";
|
out << function << "(";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
@ -510,9 +510,8 @@ const sem::Constant* ConstEval::Literal(const sem::Type* ty,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::ArrayOrStructCtor(
|
const sem::Constant* ConstEval::ArrayOrStructCtor(const sem::Type* ty,
|
||||||
const sem::Type* ty,
|
utils::VectorRef<const sem::Expression*> args) {
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) {
|
|
||||||
if (args.IsEmpty()) {
|
if (args.IsEmpty()) {
|
||||||
return ZeroValue(builder, ty);
|
return ZeroValue(builder, ty);
|
||||||
}
|
}
|
||||||
@ -532,7 +531,7 @@ const sem::Constant* ConstEval::ArrayOrStructCtor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::Conv(const sem::Type* ty,
|
const sem::Constant* ConstEval::Conv(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) {
|
utils::VectorRef<const sem::Expression*> args) {
|
||||||
uint32_t el_count = 0;
|
uint32_t el_count = 0;
|
||||||
auto* el_ty = sem::Type::ElementOf(ty, &el_count);
|
auto* el_ty = sem::Type::ElementOf(ty, &el_count);
|
||||||
if (!el_ty) {
|
if (!el_ty) {
|
||||||
@ -553,17 +552,17 @@ const sem::Constant* ConstEval::Conv(const sem::Type* ty,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::Zero(const sem::Type* ty,
|
const sem::Constant* ConstEval::Zero(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*>) {
|
utils::VectorRef<const sem::Expression*>) {
|
||||||
return ZeroValue(builder, ty);
|
return ZeroValue(builder, ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::Identity(const sem::Type*,
|
const sem::Constant* ConstEval::Identity(const sem::Type*,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) {
|
utils::VectorRef<const sem::Expression*> args) {
|
||||||
return args[0]->ConstantValue();
|
return args[0]->ConstantValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::VecSplat(const sem::Type* ty,
|
const sem::Constant* ConstEval::VecSplat(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) {
|
utils::VectorRef<const sem::Expression*> args) {
|
||||||
if (auto* arg = args[0]->ConstantValue()) {
|
if (auto* arg = args[0]->ConstantValue()) {
|
||||||
return builder.create<Splat>(ty, arg, static_cast<const sem::Vector*>(ty)->Width());
|
return builder.create<Splat>(ty, arg, static_cast<const sem::Vector*>(ty)->Width());
|
||||||
}
|
}
|
||||||
@ -571,7 +570,7 @@ const sem::Constant* ConstEval::VecSplat(const sem::Type* ty,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::VecCtorS(const sem::Type* ty,
|
const sem::Constant* ConstEval::VecCtorS(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) {
|
utils::VectorRef<const sem::Expression*> args) {
|
||||||
utils::Vector<const sem::Constant*, 4> els;
|
utils::Vector<const sem::Constant*, 4> els;
|
||||||
for (auto* arg : args) {
|
for (auto* arg : args) {
|
||||||
els.Push(arg->ConstantValue());
|
els.Push(arg->ConstantValue());
|
||||||
@ -580,7 +579,7 @@ const sem::Constant* ConstEval::VecCtorS(const sem::Type* ty,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::VecCtorM(const sem::Type* ty,
|
const sem::Constant* ConstEval::VecCtorM(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) {
|
utils::VectorRef<const sem::Expression*> args) {
|
||||||
utils::Vector<const sem::Constant*, 4> els;
|
utils::Vector<const sem::Constant*, 4> els;
|
||||||
for (auto* arg : args) {
|
for (auto* arg : args) {
|
||||||
auto* val = arg->ConstantValue();
|
auto* val = arg->ConstantValue();
|
||||||
@ -605,7 +604,7 @@ const sem::Constant* ConstEval::VecCtorM(const sem::Type* ty,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::MatCtorS(const sem::Type* ty,
|
const sem::Constant* ConstEval::MatCtorS(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) {
|
utils::VectorRef<const sem::Expression*> args) {
|
||||||
auto* m = static_cast<const sem::Matrix*>(ty);
|
auto* m = static_cast<const sem::Matrix*>(ty);
|
||||||
|
|
||||||
utils::Vector<const sem::Constant*, 4> els;
|
utils::Vector<const sem::Constant*, 4> els;
|
||||||
@ -621,7 +620,7 @@ const sem::Constant* ConstEval::MatCtorS(const sem::Type* ty,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::MatCtorV(const sem::Type* ty,
|
const sem::Constant* ConstEval::MatCtorV(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) {
|
utils::VectorRef<const sem::Expression*> args) {
|
||||||
utils::Vector<const sem::Constant*, 4> els;
|
utils::Vector<const sem::Constant*, 4> els;
|
||||||
for (auto* arg : args) {
|
for (auto* arg : args) {
|
||||||
els.Push(arg->ConstantValue());
|
els.Push(arg->ConstantValue());
|
||||||
@ -668,7 +667,7 @@ const sem::Constant* ConstEval::MemberAccess(const sem::Expression* obj_expr,
|
|||||||
|
|
||||||
const sem::Constant* ConstEval::Swizzle(const sem::Type* ty,
|
const sem::Constant* ConstEval::Swizzle(const sem::Type* ty,
|
||||||
const sem::Expression* vec_expr,
|
const sem::Expression* vec_expr,
|
||||||
utils::ConstVectorRef<uint32_t> indices) {
|
utils::VectorRef<uint32_t> indices) {
|
||||||
auto* vec_val = vec_expr->ConstantValue();
|
auto* vec_val = vec_expr->ConstantValue();
|
||||||
if (!vec_val) {
|
if (!vec_val) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -688,7 +687,7 @@ const sem::Constant* ConstEval::Bitcast(const sem::Type*, const sem::Expression*
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::OpComplement(const sem::Type*,
|
const sem::Constant* ConstEval::OpComplement(const sem::Type*,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) {
|
utils::VectorRef<const sem::Expression*> args) {
|
||||||
auto transform = [&](const sem::Constant* c) {
|
auto transform = [&](const sem::Constant* c) {
|
||||||
auto create = [&](auto i) {
|
auto create = [&](auto i) {
|
||||||
return CreateElement(builder, c->Type(), decltype(i)(~i.value));
|
return CreateElement(builder, c->Type(), decltype(i)(~i.value));
|
||||||
@ -699,7 +698,7 @@ const sem::Constant* ConstEval::OpComplement(const sem::Type*,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::OpMinus(const sem::Type*,
|
const sem::Constant* ConstEval::OpMinus(const sem::Type*,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) {
|
utils::VectorRef<const sem::Expression*> args) {
|
||||||
auto transform = [&](const sem::Constant* c) {
|
auto transform = [&](const sem::Constant* c) {
|
||||||
auto create = [&](auto i) { //
|
auto create = [&](auto i) { //
|
||||||
// For signed integrals, avoid C++ UB by not negating the
|
// For signed integrals, avoid C++ UB by not negating the
|
||||||
@ -723,7 +722,7 @@ const sem::Constant* ConstEval::OpMinus(const sem::Type*,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::atan2(const sem::Type*,
|
const sem::Constant* ConstEval::atan2(const sem::Type*,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) {
|
utils::VectorRef<const sem::Expression*> args) {
|
||||||
auto transform = [&](const sem::Constant* c0, const sem::Constant* c1) {
|
auto transform = [&](const sem::Constant* c0, const sem::Constant* c1) {
|
||||||
auto create = [&](auto i, auto j) {
|
auto create = [&](auto i, auto j) {
|
||||||
return CreateElement(builder, c0->Type(), decltype(i)(std::atan2(i.value, j.value)));
|
return CreateElement(builder, c0->Type(), decltype(i)(std::atan2(i.value, j.value)));
|
||||||
@ -735,7 +734,7 @@ const sem::Constant* ConstEval::atan2(const sem::Type*,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sem::Constant* ConstEval::clamp(const sem::Type*,
|
const sem::Constant* ConstEval::clamp(const sem::Type*,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) {
|
utils::VectorRef<const sem::Expression*> args) {
|
||||||
auto transform = [&](const sem::Constant* c0, const sem::Constant* c1,
|
auto transform = [&](const sem::Constant* c0, const sem::Constant* c1,
|
||||||
const sem::Constant* c2) {
|
const sem::Constant* c2) {
|
||||||
auto create = [&](auto e, auto low, auto high) {
|
auto create = [&](auto e, auto low, auto high) {
|
||||||
|
@ -45,8 +45,8 @@ namespace tint::resolver {
|
|||||||
class ConstEval {
|
class ConstEval {
|
||||||
public:
|
public:
|
||||||
/// Typedef for a constant evaluation function
|
/// Typedef for a constant evaluation function
|
||||||
using Function = const sem::Constant* (
|
using Function = const sem::Constant* (ConstEval::*)(const sem::Type* result_ty,
|
||||||
ConstEval::*)(const sem::Type* result_ty, utils::ConstVectorRef<const sem::Expression*>);
|
utils::VectorRef<const sem::Expression*>);
|
||||||
|
|
||||||
/// The result type of a method that may raise a diagnostic error and the caller should abort
|
/// The result type of a method that may raise a diagnostic error and the caller should abort
|
||||||
/// resolving. Can be one of three distinct values:
|
/// resolving. Can be one of three distinct values:
|
||||||
@ -71,7 +71,7 @@ class ConstEval {
|
|||||||
/// @param args the input arguments
|
/// @param args the input arguments
|
||||||
/// @return the constructed value, or null if the value cannot be calculated
|
/// @return the constructed value, or null if the value cannot be calculated
|
||||||
const sem::Constant* ArrayOrStructCtor(const sem::Type* ty,
|
const sem::Constant* ArrayOrStructCtor(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
utils::VectorRef<const sem::Expression*> args);
|
||||||
|
|
||||||
/// @param ty the target type
|
/// @param ty the target type
|
||||||
/// @param expr the input expression
|
/// @param expr the input expression
|
||||||
@ -100,7 +100,7 @@ class ConstEval {
|
|||||||
/// @return the result of the swizzle, or null if the value cannot be calculated
|
/// @return the result of the swizzle, or null if the value cannot be calculated
|
||||||
const sem::Constant* Swizzle(const sem::Type* ty,
|
const sem::Constant* Swizzle(const sem::Type* ty,
|
||||||
const sem::Expression* vector,
|
const sem::Expression* vector,
|
||||||
utils::ConstVectorRef<uint32_t> indices);
|
utils::VectorRef<uint32_t> indices);
|
||||||
|
|
||||||
/// Convert the `value` to `target_type`
|
/// Convert the `value` to `target_type`
|
||||||
/// @param ty the result type
|
/// @param ty the result type
|
||||||
@ -117,57 +117,55 @@ class ConstEval {
|
|||||||
/// @param ty the result type
|
/// @param ty the result type
|
||||||
/// @param args the input arguments
|
/// @param args the input arguments
|
||||||
/// @return the converted value, or null if the value cannot be calculated
|
/// @return the converted value, or null if the value cannot be calculated
|
||||||
const sem::Constant* Conv(const sem::Type* ty,
|
const sem::Constant* Conv(const sem::Type* ty, utils::VectorRef<const sem::Expression*> args);
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
|
||||||
|
|
||||||
/// Zero value type constructor
|
/// Zero value type constructor
|
||||||
/// @param ty the result type
|
/// @param ty the result type
|
||||||
/// @param args the input arguments (no arguments provided)
|
/// @param args the input arguments (no arguments provided)
|
||||||
/// @return the constructed value, or null if the value cannot be calculated
|
/// @return the constructed value, or null if the value cannot be calculated
|
||||||
const sem::Constant* Zero(const sem::Type* ty,
|
const sem::Constant* Zero(const sem::Type* ty, utils::VectorRef<const sem::Expression*> args);
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
|
||||||
|
|
||||||
/// Identity value type constructor
|
/// Identity value type constructor
|
||||||
/// @param ty the result type
|
/// @param ty the result type
|
||||||
/// @param args the input arguments
|
/// @param args the input arguments
|
||||||
/// @return the constructed value, or null if the value cannot be calculated
|
/// @return the constructed value, or null if the value cannot be calculated
|
||||||
const sem::Constant* Identity(const sem::Type* ty,
|
const sem::Constant* Identity(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
utils::VectorRef<const sem::Expression*> args);
|
||||||
|
|
||||||
/// Vector splat constructor
|
/// Vector splat constructor
|
||||||
/// @param ty the vector type
|
/// @param ty the vector type
|
||||||
/// @param args the input arguments
|
/// @param args the input arguments
|
||||||
/// @return the constructed value, or null if the value cannot be calculated
|
/// @return the constructed value, or null if the value cannot be calculated
|
||||||
const sem::Constant* VecSplat(const sem::Type* ty,
|
const sem::Constant* VecSplat(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
utils::VectorRef<const sem::Expression*> args);
|
||||||
|
|
||||||
/// Vector constructor using scalars
|
/// Vector constructor using scalars
|
||||||
/// @param ty the vector type
|
/// @param ty the vector type
|
||||||
/// @param args the input arguments
|
/// @param args the input arguments
|
||||||
/// @return the constructed value, or null if the value cannot be calculated
|
/// @return the constructed value, or null if the value cannot be calculated
|
||||||
const sem::Constant* VecCtorS(const sem::Type* ty,
|
const sem::Constant* VecCtorS(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
utils::VectorRef<const sem::Expression*> args);
|
||||||
|
|
||||||
/// Vector constructor using a mix of scalars and smaller vectors
|
/// Vector constructor using a mix of scalars and smaller vectors
|
||||||
/// @param ty the vector type
|
/// @param ty the vector type
|
||||||
/// @param args the input arguments
|
/// @param args the input arguments
|
||||||
/// @return the constructed value, or null if the value cannot be calculated
|
/// @return the constructed value, or null if the value cannot be calculated
|
||||||
const sem::Constant* VecCtorM(const sem::Type* ty,
|
const sem::Constant* VecCtorM(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
utils::VectorRef<const sem::Expression*> args);
|
||||||
|
|
||||||
/// Matrix constructor using scalar values
|
/// Matrix constructor using scalar values
|
||||||
/// @param ty the matrix type
|
/// @param ty the matrix type
|
||||||
/// @param args the input arguments
|
/// @param args the input arguments
|
||||||
/// @return the constructed value, or null if the value cannot be calculated
|
/// @return the constructed value, or null if the value cannot be calculated
|
||||||
const sem::Constant* MatCtorS(const sem::Type* ty,
|
const sem::Constant* MatCtorS(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
utils::VectorRef<const sem::Expression*> args);
|
||||||
|
|
||||||
/// Matrix constructor using column vectors
|
/// Matrix constructor using column vectors
|
||||||
/// @param ty the matrix type
|
/// @param ty the matrix type
|
||||||
/// @param args the input arguments
|
/// @param args the input arguments
|
||||||
/// @return the constructed value, or null if the value cannot be calculated
|
/// @return the constructed value, or null if the value cannot be calculated
|
||||||
const sem::Constant* MatCtorV(const sem::Type* ty,
|
const sem::Constant* MatCtorV(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
utils::VectorRef<const sem::Expression*> args);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Operators
|
// Operators
|
||||||
@ -178,14 +176,14 @@ class ConstEval {
|
|||||||
/// @param args the input arguments
|
/// @param args the input arguments
|
||||||
/// @return the result value, or null if the value cannot be calculated
|
/// @return the result value, or null if the value cannot be calculated
|
||||||
const sem::Constant* OpComplement(const sem::Type* ty,
|
const sem::Constant* OpComplement(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
utils::VectorRef<const sem::Expression*> args);
|
||||||
|
|
||||||
/// Minus operator '-'
|
/// Minus operator '-'
|
||||||
/// @param ty the expression type
|
/// @param ty the expression type
|
||||||
/// @param args the input arguments
|
/// @param args the input arguments
|
||||||
/// @return the result value, or null if the value cannot be calculated
|
/// @return the result value, or null if the value cannot be calculated
|
||||||
const sem::Constant* OpMinus(const sem::Type* ty,
|
const sem::Constant* OpMinus(const sem::Type* ty,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
utils::VectorRef<const sem::Expression*> args);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Builtins
|
// Builtins
|
||||||
@ -195,15 +193,13 @@ class ConstEval {
|
|||||||
/// @param ty the expression type
|
/// @param ty the expression type
|
||||||
/// @param args the input arguments
|
/// @param args the input arguments
|
||||||
/// @return the result value, or null if the value cannot be calculated
|
/// @return the result value, or null if the value cannot be calculated
|
||||||
const sem::Constant* atan2(const sem::Type* ty,
|
const sem::Constant* atan2(const sem::Type* ty, utils::VectorRef<const sem::Expression*> args);
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
|
||||||
|
|
||||||
/// clamp builtin
|
/// clamp builtin
|
||||||
/// @param ty the expression type
|
/// @param ty the expression type
|
||||||
/// @param args the input arguments
|
/// @param args the input arguments
|
||||||
/// @return the result value, or null if the value cannot be calculated
|
/// @return the result value, or null if the value cannot be calculated
|
||||||
const sem::Constant* clamp(const sem::Type* ty,
|
const sem::Constant* clamp(const sem::Type* ty, utils::VectorRef<const sem::Expression*> args);
|
||||||
utils::ConstVectorRef<const sem::Expression*> args);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Adds the given error message to the diagnostics
|
/// Adds the given error message to the diagnostics
|
||||||
|
@ -1026,14 +1026,14 @@ class Impl : public IntrinsicTable {
|
|||||||
|
|
||||||
// Prints the list of candidates for emitting diagnostics
|
// Prints the list of candidates for emitting diagnostics
|
||||||
void PrintCandidates(std::ostream& ss,
|
void PrintCandidates(std::ostream& ss,
|
||||||
utils::ConstVectorRef<Candidate> candidates,
|
utils::VectorRef<Candidate> candidates,
|
||||||
const char* intrinsic_name) const;
|
const char* intrinsic_name) const;
|
||||||
|
|
||||||
/// Raises an error when no overload is a clear winner of overload resolution
|
/// Raises an error when no overload is a clear winner of overload resolution
|
||||||
void ErrAmbiguousOverload(const char* intrinsic_name,
|
void ErrAmbiguousOverload(const char* intrinsic_name,
|
||||||
utils::ConstVectorRef<const sem::Type*> args,
|
utils::VectorRef<const sem::Type*> args,
|
||||||
TemplateState templates,
|
TemplateState templates,
|
||||||
utils::ConstVectorRef<Candidate> candidates) const;
|
utils::VectorRef<Candidate> candidates) const;
|
||||||
|
|
||||||
ProgramBuilder& builder;
|
ProgramBuilder& builder;
|
||||||
Matchers matchers;
|
Matchers matchers;
|
||||||
@ -1604,7 +1604,7 @@ void Impl::PrintOverload(std::ostream& ss,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Impl::PrintCandidates(std::ostream& ss,
|
void Impl::PrintCandidates(std::ostream& ss,
|
||||||
utils::ConstVectorRef<Candidate> candidates,
|
utils::VectorRef<Candidate> candidates,
|
||||||
const char* intrinsic_name) const {
|
const char* intrinsic_name) const {
|
||||||
for (auto& candidate : candidates) {
|
for (auto& candidate : candidates) {
|
||||||
ss << " ";
|
ss << " ";
|
||||||
@ -1638,9 +1638,9 @@ std::string MatchState::NumName() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Impl::ErrAmbiguousOverload(const char* intrinsic_name,
|
void Impl::ErrAmbiguousOverload(const char* intrinsic_name,
|
||||||
utils::ConstVectorRef<const sem::Type*> args,
|
utils::VectorRef<const sem::Type*> args,
|
||||||
TemplateState templates,
|
TemplateState templates,
|
||||||
utils::ConstVectorRef<Candidate> candidates) const {
|
utils::VectorRef<Candidate> candidates) const {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "ambiguous overload while attempting to match " << intrinsic_name;
|
ss << "ambiguous overload while attempting to match " << intrinsic_name;
|
||||||
for (size_t i = 0; i < std::numeric_limits<size_t>::max(); i++) {
|
for (size_t i = 0; i < std::numeric_limits<size_t>::max(); i++) {
|
||||||
|
@ -1406,7 +1406,8 @@ const sem::Expression* Resolver::Materialize(const sem::Expression* expr,
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::MaterializeArguments(utils::VectorRef<const sem::Expression*> args,
|
template <size_t N>
|
||||||
|
bool Resolver::MaterializeArguments(utils::Vector<const sem::Expression*, N>& args,
|
||||||
const sem::CallTarget* target) {
|
const sem::CallTarget* target) {
|
||||||
for (size_t i = 0, n = std::min(args.Length(), target->Parameters().Length()); i < n; i++) {
|
for (size_t i = 0, n = std::min(args.Length(), target->Parameters().Length()); i < n; i++) {
|
||||||
const auto* param_ty = target->Parameters()[i]->Type();
|
const auto* param_ty = target->Parameters()[i]->Type();
|
||||||
@ -1778,9 +1779,7 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
|||||||
// there's no need to infer element types.
|
// there's no need to infer element types.
|
||||||
return ty_ctor_or_conv(ty);
|
return ty_ctor_or_conv(ty);
|
||||||
},
|
},
|
||||||
[&](sem::Function* func) {
|
[&](sem::Function* func) { return FunctionCall(expr, func, args, arg_behaviors); },
|
||||||
return FunctionCall(expr, func, std::move(args), arg_behaviors);
|
|
||||||
},
|
|
||||||
[&](sem::Variable* var) {
|
[&](sem::Variable* var) {
|
||||||
auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
|
auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
|
||||||
AddError("cannot call variable '" + name + "'", ident->source);
|
AddError("cannot call variable '" + name + "'", ident->source);
|
||||||
@ -1791,7 +1790,7 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
|||||||
auto name = builder_->Symbols().NameFor(ident->symbol);
|
auto name = builder_->Symbols().NameFor(ident->symbol);
|
||||||
auto builtin_type = sem::ParseBuiltinType(name);
|
auto builtin_type = sem::ParseBuiltinType(name);
|
||||||
if (builtin_type != sem::BuiltinType::kNone) {
|
if (builtin_type != sem::BuiltinType::kNone) {
|
||||||
return BuiltinCall(expr, builtin_type, std::move(args));
|
return BuiltinCall(expr, builtin_type, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
TINT_ICE(Resolver, diagnostics_)
|
TINT_ICE(Resolver, diagnostics_)
|
||||||
@ -1809,12 +1808,13 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
|||||||
return validator_.Call(call, current_statement_) ? call : nullptr;
|
return validator_.Call(call, current_statement_) ? call : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
|
sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
|
||||||
sem::BuiltinType builtin_type,
|
sem::BuiltinType builtin_type,
|
||||||
utils::VectorRef<const sem::Expression*> args) {
|
utils::Vector<const sem::Expression*, N>& args) {
|
||||||
IntrinsicTable::Builtin builtin;
|
IntrinsicTable::Builtin builtin;
|
||||||
{
|
{
|
||||||
auto arg_tys = utils::Transform<8>(args, [](auto* arg) { return arg->Type(); });
|
auto arg_tys = utils::Transform(args, [](auto* arg) { return arg->Type(); });
|
||||||
builtin = intrinsic_table_->Lookup(builtin_type, arg_tys, expr->source);
|
builtin = intrinsic_table_->Lookup(builtin_type, arg_tys, expr->source);
|
||||||
if (!builtin.sem) {
|
if (!builtin.sem) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -1876,9 +1876,8 @@ sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
|
|||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Resolver::CollectTextureSamplerPairs(
|
void Resolver::CollectTextureSamplerPairs(const sem::Builtin* builtin,
|
||||||
const sem::Builtin* builtin,
|
utils::VectorRef<const sem::Expression*> args) const {
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) const {
|
|
||||||
// Collect a texture/sampler pair for this builtin.
|
// Collect a texture/sampler pair for this builtin.
|
||||||
const auto& signature = builtin->Signature();
|
const auto& signature = builtin->Signature();
|
||||||
int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
|
int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
|
||||||
@ -1896,9 +1895,10 @@ void Resolver::CollectTextureSamplerPairs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr,
|
sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr,
|
||||||
sem::Function* target,
|
sem::Function* target,
|
||||||
utils::VectorRef<const sem::Expression*> args,
|
utils::Vector<const sem::Expression*, N>& args,
|
||||||
sem::Behaviors arg_behaviors) {
|
sem::Behaviors arg_behaviors) {
|
||||||
auto sym = expr->target.name->symbol;
|
auto sym = expr->target.name->symbol;
|
||||||
auto name = builder_->Symbols().NameFor(sym);
|
auto name = builder_->Symbols().NameFor(sym);
|
||||||
@ -1944,9 +1944,8 @@ sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr,
|
|||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Resolver::CollectTextureSamplerPairs(
|
void Resolver::CollectTextureSamplerPairs(sem::Function* func,
|
||||||
sem::Function* func,
|
utils::VectorRef<const sem::Expression*> args) const {
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) const {
|
|
||||||
// Map all texture/sampler pairs from the target function to the
|
// Map all texture/sampler pairs from the target function to the
|
||||||
// current function. These can only be global or parameter
|
// current function. These can only be global or parameter
|
||||||
// variables. Resolve any parameter variables to the corresponding
|
// variables. Resolve any parameter variables to the corresponding
|
||||||
|
@ -193,14 +193,16 @@ class Resolver {
|
|||||||
sem::Expression* Bitcast(const ast::BitcastExpression*);
|
sem::Expression* Bitcast(const ast::BitcastExpression*);
|
||||||
sem::Call* Call(const ast::CallExpression*);
|
sem::Call* Call(const ast::CallExpression*);
|
||||||
sem::Function* Function(const ast::Function*);
|
sem::Function* Function(const ast::Function*);
|
||||||
|
template <size_t N>
|
||||||
sem::Call* FunctionCall(const ast::CallExpression*,
|
sem::Call* FunctionCall(const ast::CallExpression*,
|
||||||
sem::Function* target,
|
sem::Function* target,
|
||||||
utils::VectorRef<const sem::Expression*> args,
|
utils::Vector<const sem::Expression*, N>& args,
|
||||||
sem::Behaviors arg_behaviors);
|
sem::Behaviors arg_behaviors);
|
||||||
sem::Expression* Identifier(const ast::IdentifierExpression*);
|
sem::Expression* Identifier(const ast::IdentifierExpression*);
|
||||||
|
template <size_t N>
|
||||||
sem::Call* BuiltinCall(const ast::CallExpression*,
|
sem::Call* BuiltinCall(const ast::CallExpression*,
|
||||||
sem::BuiltinType,
|
sem::BuiltinType,
|
||||||
utils::VectorRef<const sem::Expression*> args);
|
utils::Vector<const sem::Expression*, N>& args);
|
||||||
sem::Expression* Literal(const ast::LiteralExpression*);
|
sem::Expression* Literal(const ast::LiteralExpression*);
|
||||||
sem::Expression* MemberAccessor(const ast::MemberAccessorExpression*);
|
sem::Expression* MemberAccessor(const ast::MemberAccessorExpression*);
|
||||||
sem::Expression* UnaryOp(const ast::UnaryOpExpression*);
|
sem::Expression* UnaryOp(const ast::UnaryOpExpression*);
|
||||||
@ -223,7 +225,8 @@ class Resolver {
|
|||||||
|
|
||||||
/// Materializes all the arguments in `args` to the parameter types of `target`.
|
/// Materializes all the arguments in `args` to the parameter types of `target`.
|
||||||
/// @returns true on success, false on failure.
|
/// @returns true on success, false on failure.
|
||||||
bool MaterializeArguments(utils::VectorRef<const sem::Expression*> args,
|
template <size_t N>
|
||||||
|
bool MaterializeArguments(utils::Vector<const sem::Expression*, N>& args,
|
||||||
const sem::CallTarget* target);
|
const sem::CallTarget* target);
|
||||||
|
|
||||||
/// @returns true if an argument of an abstract numeric type, passed to a parameter of type
|
/// @returns true if an argument of an abstract numeric type, passed to a parameter of type
|
||||||
@ -267,9 +270,9 @@ class Resolver {
|
|||||||
// CollectTextureSamplerPairs() collects all the texture/sampler pairs from the target function
|
// CollectTextureSamplerPairs() collects all the texture/sampler pairs from the target function
|
||||||
// / builtin, and records these on the current function by calling AddTextureSamplerPair().
|
// / builtin, and records these on the current function by calling AddTextureSamplerPair().
|
||||||
void CollectTextureSamplerPairs(sem::Function* func,
|
void CollectTextureSamplerPairs(sem::Function* func,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) const;
|
utils::VectorRef<const sem::Expression*> args) const;
|
||||||
void CollectTextureSamplerPairs(const sem::Builtin* builtin,
|
void CollectTextureSamplerPairs(const sem::Builtin* builtin,
|
||||||
utils::ConstVectorRef<const sem::Expression*> args) const;
|
utils::VectorRef<const sem::Expression*> args) const;
|
||||||
|
|
||||||
/// Resolves the WorkgroupSize for the given function, assigning it to
|
/// Resolves the WorkgroupSize for the given function, assigning it to
|
||||||
/// current_function_
|
/// current_function_
|
||||||
|
@ -272,7 +272,7 @@ const Type* Type::DeepestElementOf(const Type* ty, uint32_t* count /* = nullptr
|
|||||||
return el_ty;
|
return el_ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sem::Type* Type::Common(utils::ConstVectorRef<const Type*> types) {
|
const sem::Type* Type::Common(utils::VectorRef<const Type*> types) {
|
||||||
const auto count = types.Length();
|
const auto count = types.Length();
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -161,7 +161,7 @@ class Type : public Castable<Type, Node> {
|
|||||||
/// @returns the lowest-ranking type that all types in `types` can be implicitly converted to,
|
/// @returns the lowest-ranking type that all types in `types` can be implicitly converted to,
|
||||||
/// or nullptr if there is no consistent common type across all types in `types`.
|
/// or nullptr if there is no consistent common type across all types in `types`.
|
||||||
/// @see https://www.w3.org/TR/WGSL/#conversion-rank
|
/// @see https://www.w3.org/TR/WGSL/#conversion-rank
|
||||||
static const sem::Type* Common(utils::ConstVectorRef<const Type*> types);
|
static const sem::Type* Common(utils::VectorRef<const Type*> types);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Type();
|
Type();
|
||||||
|
@ -119,40 +119,6 @@ auto Transform(const VectorRef<IN>& in, TRANSFORMER&& transform)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transform performs an element-wise transformation of a vector reference.
|
|
||||||
/// @param in the input vector.
|
|
||||||
/// @param transform the transformation function with signature: `OUT(IN)`
|
|
||||||
/// @tparam N the small-array size of the returned Vector
|
|
||||||
/// @returns a new vector with each element of the source vector transformed by `transform`.
|
|
||||||
template <size_t N, typename IN, typename TRANSFORMER>
|
|
||||||
auto Transform(ConstVectorRef<IN> in, TRANSFORMER&& transform)
|
|
||||||
-> Vector<decltype(transform(in[0])), N> {
|
|
||||||
const auto count = in.Length();
|
|
||||||
Vector<decltype(transform(in[0])), N> result;
|
|
||||||
result.Reserve(count);
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
result.Push(transform(in[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transform performs an element-wise transformation of a vector reference.
|
|
||||||
/// @param in the input vector.
|
|
||||||
/// @param transform the transformation function with signature: `OUT(IN, size_t)`
|
|
||||||
/// @tparam N the small-array size of the returned Vector
|
|
||||||
/// @returns a new vector with each element of the source vector transformed by `transform`.
|
|
||||||
template <size_t N, typename IN, typename TRANSFORMER>
|
|
||||||
auto Transform(ConstVectorRef<IN> in, TRANSFORMER&& transform)
|
|
||||||
-> Vector<decltype(transform(in[0], 1u)), N> {
|
|
||||||
const auto count = in.Length();
|
|
||||||
Vector<decltype(transform(in[0], 1u)), N> result;
|
|
||||||
result.Reserve(count);
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
result.Push(transform(in[i], i));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TransformN performs an element-wise transformation of a vector, transforming and returning at
|
/// TransformN performs an element-wise transformation of a vector, transforming and returning at
|
||||||
/// most `n` elements.
|
/// most `n` elements.
|
||||||
/// @param in the input vector.
|
/// @param in the input vector.
|
||||||
|
@ -345,72 +345,5 @@ TEST(TransformTest, TransformVectorRefDifferentType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TransformTest, ConstVectorRefEmpty) {
|
|
||||||
const Vector<int, 4> empty{};
|
|
||||||
ConstVectorRef<int> ref(empty);
|
|
||||||
{
|
|
||||||
auto transformed = Transform<4>(ref, [](int) -> int {
|
|
||||||
[] { FAIL() << "Callback should not be called for empty vector"; }();
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
CHECK_ELEMENT_TYPE(transformed, int);
|
|
||||||
EXPECT_EQ(transformed.Length(), 0u);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto transformed = Transform<4>(ref, [](int, size_t) -> int {
|
|
||||||
[] { FAIL() << "Callback should not be called for empty vector"; }();
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
CHECK_ELEMENT_TYPE(transformed, int);
|
|
||||||
EXPECT_EQ(transformed.Length(), 0u);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TransformTest, ConstVectorRefIdentity) {
|
|
||||||
const Vector<int, 4> input{1, 2, 3, 4};
|
|
||||||
ConstVectorRef<int> ref(input);
|
|
||||||
auto transformed = Transform<8>(ref, [](int i) { return i; });
|
|
||||||
CHECK_ELEMENT_TYPE(transformed, int);
|
|
||||||
EXPECT_THAT(transformed, testing::ElementsAre(1, 2, 3, 4));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TransformTest, ConstVectorRefIdentityWithIndex) {
|
|
||||||
const Vector<int, 4> input{1, 2, 3, 4};
|
|
||||||
ConstVectorRef<int> ref(input);
|
|
||||||
auto transformed = Transform<2>(ref, [](int i, size_t) { return i; });
|
|
||||||
CHECK_ELEMENT_TYPE(transformed, int);
|
|
||||||
EXPECT_THAT(transformed, testing::ElementsAre(1, 2, 3, 4));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TransformTest, ConstVectorRefIndex) {
|
|
||||||
const Vector<int, 4> input{10, 20, 30, 40};
|
|
||||||
ConstVectorRef<int> ref(input);
|
|
||||||
{
|
|
||||||
auto transformed = Transform<4>(ref, [](int, size_t idx) { return idx; });
|
|
||||||
CHECK_ELEMENT_TYPE(transformed, size_t);
|
|
||||||
EXPECT_THAT(transformed, testing::ElementsAre(0u, 1u, 2u, 3u));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TransformTest, TransformConstVectorRefSameType) {
|
|
||||||
const Vector<int, 4> input{1, 2, 3, 4};
|
|
||||||
ConstVectorRef<int> ref(input);
|
|
||||||
{
|
|
||||||
auto transformed = Transform<4>(ref, [](int i) { return i * 10; });
|
|
||||||
CHECK_ELEMENT_TYPE(transformed, int);
|
|
||||||
EXPECT_THAT(transformed, testing::ElementsAre(10, 20, 30, 40));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TransformTest, TransformConstVectorRefDifferentType) {
|
|
||||||
const Vector<int, 4> input{1, 2, 3, 4};
|
|
||||||
ConstVectorRef<int> ref(input);
|
|
||||||
{
|
|
||||||
auto transformed = Transform<4>(ref, [](int i) { return std::to_string(i); });
|
|
||||||
CHECK_ELEMENT_TYPE(transformed, std::string);
|
|
||||||
EXPECT_THAT(transformed, testing::ElementsAre("1", "2", "3", "4"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace tint::utils
|
} // namespace tint::utils
|
||||||
|
@ -32,12 +32,18 @@ namespace tint::utils {
|
|||||||
template <typename>
|
template <typename>
|
||||||
class VectorRef;
|
class VectorRef;
|
||||||
template <typename>
|
template <typename>
|
||||||
class ConstVectorRef;
|
class VectorRef;
|
||||||
|
|
||||||
} // namespace tint::utils
|
} // namespace tint::utils
|
||||||
|
|
||||||
namespace tint::utils {
|
namespace tint::utils {
|
||||||
|
|
||||||
|
/// A type used to indicate an empty array.
|
||||||
|
struct EmptyType {};
|
||||||
|
|
||||||
|
/// An instance of the EmptyType.
|
||||||
|
static constexpr EmptyType Empty;
|
||||||
|
|
||||||
/// A slice represents a contigious array of elements of type T.
|
/// A slice represents a contigious array of elements of type T.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Slice {
|
struct Slice {
|
||||||
@ -164,6 +170,9 @@ class Vector {
|
|||||||
/// Constructor
|
/// Constructor
|
||||||
Vector() = default;
|
Vector() = default;
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
Vector(EmptyType) {} // NOLINT(runtime/explicit)
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param elements the elements to place into the vector
|
/// @param elements the elements to place into the vector
|
||||||
Vector(std::initializer_list<T> elements) {
|
Vector(std::initializer_list<T> elements) {
|
||||||
@ -217,10 +226,7 @@ class Vector {
|
|||||||
|
|
||||||
/// Copy constructor from an immutable vector reference
|
/// Copy constructor from an immutable vector reference
|
||||||
/// @param other the vector reference to copy
|
/// @param other the vector reference to copy
|
||||||
explicit Vector(const ConstVectorRef<T>& other) { Copy(other.slice_); }
|
explicit Vector(const VectorRef<T>& other) { Copy(other.slice_); }
|
||||||
|
|
||||||
/// Move constructor from an immutable vector reference (invalid)
|
|
||||||
Vector(ConstVectorRef<T>&&) = delete; // NOLINT(runtime/explicit)
|
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Vector() { ClearAndFree(); }
|
~Vector() { ClearAndFree(); }
|
||||||
@ -263,6 +269,26 @@ class Vector {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Assignment operator (differing N length)
|
||||||
|
/// @param other the vector reference to copy
|
||||||
|
/// @returns this vector so calls can be chained
|
||||||
|
Vector& operator=(const VectorRef<T>& other) {
|
||||||
|
if (&other.slice_ != &impl_.slice) {
|
||||||
|
Copy(other.slice_);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move operator (differing N length)
|
||||||
|
/// @param other the vector reference to copy
|
||||||
|
/// @returns this vector so calls can be chained
|
||||||
|
Vector& operator=(VectorRef<T>&& other) {
|
||||||
|
if (&other.slice_ != &impl_.slice) {
|
||||||
|
MoveOrCopy(std::move(other));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/// Index operator
|
/// Index operator
|
||||||
/// @param i the element index. Must be less than `len`.
|
/// @param i the element index. Must be less than `len`.
|
||||||
/// @returns a reference to the i'th element.
|
/// @returns a reference to the i'th element.
|
||||||
@ -367,7 +393,12 @@ class Vector {
|
|||||||
|
|
||||||
/// Removes and returns the last element from the vector.
|
/// Removes and returns the last element from the vector.
|
||||||
/// @returns the popped element
|
/// @returns the popped element
|
||||||
T Pop() { return std::move(impl_.slice.data[--impl_.slice.len]); }
|
T Pop() {
|
||||||
|
auto& el = impl_.slice.data[--impl_.slice.len];
|
||||||
|
auto val = std::move(el);
|
||||||
|
el.~T();
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
/// @returns true if the vector is empty.
|
/// @returns true if the vector is empty.
|
||||||
bool IsEmpty() const { return impl_.slice.len == 0; }
|
bool IsEmpty() const { return impl_.slice.len == 0; }
|
||||||
@ -419,7 +450,7 @@ class Vector {
|
|||||||
|
|
||||||
/// Friend class
|
/// Friend class
|
||||||
template <typename>
|
template <typename>
|
||||||
friend class ConstVectorRef;
|
friend class VectorRef;
|
||||||
|
|
||||||
/// The slice type used by this vector
|
/// The slice type used by this vector
|
||||||
using Slice = utils::Slice<T>;
|
using Slice = utils::Slice<T>;
|
||||||
@ -573,11 +604,10 @@ Vector(Ts...) -> Vector<VectorCommonType<Ts...>, sizeof...(Ts)>;
|
|||||||
|
|
||||||
/// VectorRef is a weak reference to a Vector, used to pass vectors as parameters, avoiding copies
|
/// VectorRef is a weak reference to a Vector, used to pass vectors as parameters, avoiding copies
|
||||||
/// between the caller and the callee. VectorRef can accept a Vector of any 'N' value, decoupling
|
/// between the caller and the callee. VectorRef can accept a Vector of any 'N' value, decoupling
|
||||||
/// the caller's vector internal size from the callee's vector size.
|
/// the caller's vector internal size from the callee's vector size. A VectorRef tracks the usage of
|
||||||
///
|
/// moves either side of the call. If at the call site, a Vector argument is moved to a VectorRef
|
||||||
/// A VectorRef tracks the usage of moves either side of the call. If at the call site, a Vector
|
/// parameter, and within the callee, the VectorRef parameter is moved to a Vector, then the Vector
|
||||||
/// argument is moved to a VectorRef parameter, and within the callee, the VectorRef parameter is
|
/// heap allocation will be moved. For example:
|
||||||
/// moved to a Vector, then the Vector heap allocation will be moved. For example:
|
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// void func_a() {
|
/// void func_a() {
|
||||||
@ -596,12 +626,30 @@ class VectorRef {
|
|||||||
/// The slice type used by this vector reference
|
/// The slice type used by this vector reference
|
||||||
using Slice = utils::Slice<T>;
|
using Slice = utils::Slice<T>;
|
||||||
|
|
||||||
|
/// @returns an empty slice.
|
||||||
|
static Slice& EmptySlice() {
|
||||||
|
static Slice empty;
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// Constructor - empty reference
|
||||||
|
VectorRef() : slice_(EmptySlice()) {}
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
VectorRef(EmptyType) : slice_(EmptySlice()) {} // NOLINT(runtime/explicit)
|
||||||
|
|
||||||
/// Constructor from a Vector
|
/// Constructor from a Vector
|
||||||
/// @param vector the vector to create a reference of
|
/// @param vector the vector to create a reference of
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
VectorRef(Vector<T, N>& vector) // NOLINT(runtime/explicit)
|
VectorRef(Vector<T, N>& vector) // NOLINT(runtime/explicit)
|
||||||
: slice_(vector.impl_.slice), can_move_(false) {}
|
: slice_(vector.impl_.slice) {}
|
||||||
|
|
||||||
|
/// Constructor from a const Vector
|
||||||
|
/// @param vector the vector to create a reference of
|
||||||
|
template <size_t N>
|
||||||
|
VectorRef(const Vector<T, N>& vector) // NOLINT(runtime/explicit)
|
||||||
|
: slice_(const_cast<Slice&>(vector.impl_.slice)) {}
|
||||||
|
|
||||||
/// Constructor from a moved Vector
|
/// Constructor from a moved Vector
|
||||||
/// @param vector the vector being moved
|
/// @param vector the vector being moved
|
||||||
@ -611,7 +659,7 @@ class VectorRef {
|
|||||||
|
|
||||||
/// Copy constructor
|
/// Copy constructor
|
||||||
/// @param other the vector reference
|
/// @param other the vector reference
|
||||||
VectorRef(const VectorRef& other) : slice_(other.slice_), can_move_(false) {}
|
VectorRef(const VectorRef& other) : slice_(other.slice_) {}
|
||||||
|
|
||||||
/// Move constructor
|
/// Move constructor
|
||||||
/// @param other the vector reference
|
/// @param other the vector reference
|
||||||
@ -621,7 +669,7 @@ class VectorRef {
|
|||||||
/// @param other the other vector reference
|
/// @param other the other vector reference
|
||||||
template <typename U, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
template <typename U, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
||||||
VectorRef(const VectorRef<U>& other) // NOLINT(runtime/explicit)
|
VectorRef(const VectorRef<U>& other) // NOLINT(runtime/explicit)
|
||||||
: slice_(*ReinterpretSlice<T>(&other.slice_)), can_move_(false) {}
|
: slice_(*ReinterpretSlice<T>(&other.slice_)) {}
|
||||||
|
|
||||||
/// Move constructor with covariance / const conversion
|
/// Move constructor with covariance / const conversion
|
||||||
/// @param other the vector reference
|
/// @param other the vector reference
|
||||||
@ -634,7 +682,7 @@ class VectorRef {
|
|||||||
/// @see CanReinterpretSlice for rules about conversion
|
/// @see CanReinterpretSlice for rules about conversion
|
||||||
template <typename U, size_t N, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
template <typename U, size_t N, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
||||||
VectorRef(Vector<U, N>& vector) // NOLINT(runtime/explicit)
|
VectorRef(Vector<U, N>& vector) // NOLINT(runtime/explicit)
|
||||||
: slice_(*ReinterpretSlice<T>(&vector.impl_.slice)), can_move_(false) {}
|
: slice_(*ReinterpretSlice<T>(&vector.impl_.slice)) {}
|
||||||
|
|
||||||
/// Constructor from a moved Vector with covariance / const conversion
|
/// Constructor from a moved Vector with covariance / const conversion
|
||||||
/// @param vector the vector to create a reference of
|
/// @param vector the vector to create a reference of
|
||||||
@ -643,11 +691,6 @@ class VectorRef {
|
|||||||
VectorRef(Vector<U, N>&& vector) // NOLINT(runtime/explicit)
|
VectorRef(Vector<U, N>&& vector) // NOLINT(runtime/explicit)
|
||||||
: slice_(*ReinterpretSlice<T>(&vector.impl_.slice)), can_move_(vector.impl_.CanMove()) {}
|
: slice_(*ReinterpretSlice<T>(&vector.impl_.slice)), can_move_(vector.impl_.CanMove()) {}
|
||||||
|
|
||||||
/// Index operator
|
|
||||||
/// @param i the element index. Must be less than `len`.
|
|
||||||
/// @returns a reference to the i'th element.
|
|
||||||
T& operator[](size_t i) { return slice_[i]; }
|
|
||||||
|
|
||||||
/// Index operator
|
/// Index operator
|
||||||
/// @param i the element index. Must be less than `len`.
|
/// @param i the element index. Must be less than `len`.
|
||||||
/// @returns a reference to the i'th element.
|
/// @returns a reference to the i'th element.
|
||||||
@ -710,7 +753,7 @@ class VectorRef {
|
|||||||
|
|
||||||
/// Friend class
|
/// Friend class
|
||||||
template <typename>
|
template <typename>
|
||||||
friend class ConstVectorRef;
|
friend class VectorRef;
|
||||||
|
|
||||||
/// The slice of the vector being referenced.
|
/// The slice of the vector being referenced.
|
||||||
Slice& slice_;
|
Slice& slice_;
|
||||||
@ -718,99 +761,6 @@ class VectorRef {
|
|||||||
bool can_move_ = false;
|
bool can_move_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// ConstVectorRef is a weak, immutable reference to a Vector, used to pass vectors as parameters,
|
|
||||||
/// avoiding copies between the caller and the callee. VectorRef can accept a Vector of any 'N'
|
|
||||||
/// value, decoupling the caller's vector internal size from the callee's vector size.
|
|
||||||
template <typename T>
|
|
||||||
class ConstVectorRef {
|
|
||||||
/// The slice type used by this vector reference
|
|
||||||
using Slice = utils::Slice<T>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// Constructor from a Vector.
|
|
||||||
/// @param vector the vector reference
|
|
||||||
template <size_t N>
|
|
||||||
ConstVectorRef(const Vector<T, N>& vector) // NOLINT(runtime/explicit)
|
|
||||||
: slice_(vector.impl_.slice) {}
|
|
||||||
|
|
||||||
/// Copy constructor
|
|
||||||
/// @param other the vector reference
|
|
||||||
ConstVectorRef(const ConstVectorRef& other) = default;
|
|
||||||
|
|
||||||
/// Conversion constructor to convert from a non-const to const vector reference
|
|
||||||
/// @param other the vector reference
|
|
||||||
ConstVectorRef(const VectorRef<T>& other) : slice_(other.slice_) {} // NOLINT(runtime/explicit)
|
|
||||||
|
|
||||||
/// Move constructor. Deleted as this won't move anything.
|
|
||||||
ConstVectorRef(ConstVectorRef&&) = delete;
|
|
||||||
|
|
||||||
/// Constructor from a Vector with covariance / const conversion
|
|
||||||
/// @param vector the vector to create a reference of
|
|
||||||
/// @see CanReinterpretSlice for rules about conversion
|
|
||||||
template <typename U, size_t N, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
|
||||||
ConstVectorRef(const Vector<U, N>& vector) // NOLINT(runtime/explicit)
|
|
||||||
: slice_(*ReinterpretSlice<T>(&vector.impl_.slice)) {}
|
|
||||||
|
|
||||||
/// Constructor from a VectorRef with covariance / const conversion
|
|
||||||
/// @param other the vector reference
|
|
||||||
/// @see CanReinterpretSlice for rules about conversion
|
|
||||||
template <typename U, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
|
||||||
ConstVectorRef(const VectorRef<U>& other) // NOLINT(runtime/explicit)
|
|
||||||
: slice_(*ReinterpretSlice<T>(&other.slice_)) {}
|
|
||||||
|
|
||||||
/// Constructor from a ConstVectorRef with covariance / const conversion
|
|
||||||
/// @param other the vector reference
|
|
||||||
/// @see CanReinterpretSlice for rules about conversion
|
|
||||||
template <typename U, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
|
|
||||||
ConstVectorRef(const ConstVectorRef<U>& other) // NOLINT(runtime/explicit)
|
|
||||||
: slice_(*ReinterpretSlice<T>(&other.slice_)) {}
|
|
||||||
|
|
||||||
/// Index operator
|
|
||||||
/// @param i the element index. Must be less than `len`.
|
|
||||||
/// @returns a reference to the i'th element.
|
|
||||||
const T& operator[](size_t i) const { return slice_[i]; }
|
|
||||||
|
|
||||||
/// @return the number of elements in the vector
|
|
||||||
size_t Length() const { return slice_.len; }
|
|
||||||
|
|
||||||
/// @return the number of elements that the vector could hold before a heap allocation needs to
|
|
||||||
/// be made
|
|
||||||
size_t Capacity() const { return slice_.cap; }
|
|
||||||
|
|
||||||
/// @returns true if the vector is empty.
|
|
||||||
bool IsEmpty() const { return slice_.len == 0; }
|
|
||||||
|
|
||||||
/// @returns a reference to the first element in the vector
|
|
||||||
const T& Front() const { return slice_.Front(); }
|
|
||||||
|
|
||||||
/// @returns a reference to the last element in the vector
|
|
||||||
const T& Back() const { return slice_.Back(); }
|
|
||||||
|
|
||||||
/// @returns a pointer to the first element in the vector
|
|
||||||
const T* begin() const { return slice_.begin(); }
|
|
||||||
|
|
||||||
/// @returns a pointer to one past the last element in the vector
|
|
||||||
const T* end() const { return slice_.end(); }
|
|
||||||
|
|
||||||
/// @returns a reverse iterator starting with the last element in the vector
|
|
||||||
auto rbegin() const { return slice_.rbegin(); }
|
|
||||||
|
|
||||||
/// @returns the end for a reverse iterator
|
|
||||||
auto rend() const { return slice_.rend(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Friend class
|
|
||||||
template <typename, size_t>
|
|
||||||
friend class Vector;
|
|
||||||
|
|
||||||
/// Friend class
|
|
||||||
template <typename>
|
|
||||||
friend class ConstVectorRef;
|
|
||||||
|
|
||||||
/// The slice of the vector being referenced.
|
|
||||||
const Slice& slice_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Helper for converting a Vector to a std::vector.
|
/// Helper for converting a Vector to a std::vector.
|
||||||
/// @note This helper exists to help code migration. Avoid if possible.
|
/// @note This helper exists to help code migration. Avoid if possible.
|
||||||
template <typename T, size_t N>
|
template <typename T, size_t N>
|
||||||
|
@ -105,12 +105,24 @@ TEST(TintVectorTest, SmallArray_Empty) {
|
|||||||
EXPECT_EQ(vec.Capacity(), 2u);
|
EXPECT_EQ(vec.Capacity(), 2u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TintVectorTest, Empty_NoSmallArray) {
|
TEST(TintVectorTest, NoSmallArray) {
|
||||||
Vector<int, 0> vec;
|
Vector<int, 0> vec;
|
||||||
EXPECT_EQ(vec.Length(), 0u);
|
EXPECT_EQ(vec.Length(), 0u);
|
||||||
EXPECT_EQ(vec.Capacity(), 0u);
|
EXPECT_EQ(vec.Capacity(), 0u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, Empty_SmallArray_Empty) {
|
||||||
|
Vector<int, 2> vec(Empty);
|
||||||
|
EXPECT_EQ(vec.Length(), 0u);
|
||||||
|
EXPECT_EQ(vec.Capacity(), 2u);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, Empty_NoSmallArray) {
|
||||||
|
Vector<int, 0> vec(Empty);
|
||||||
|
EXPECT_EQ(vec.Length(), 0u);
|
||||||
|
EXPECT_EQ(vec.Capacity(), 0u);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(TintVectorTest, InitializerList_NoSpill) {
|
TEST(TintVectorTest, InitializerList_NoSpill) {
|
||||||
Vector<std::string, 2> vec{"one", "two"};
|
Vector<std::string, 2> vec{"one", "two"};
|
||||||
EXPECT_EQ(vec.Length(), 2u);
|
EXPECT_EQ(vec.Length(), 2u);
|
||||||
@ -800,7 +812,7 @@ TEST(TintVectorTest, RepeatMoveAssign_NoSpill) {
|
|||||||
EXPECT_TRUE(AllInternallyHeld(vec));
|
EXPECT_TRUE(AllInternallyHeld(vec));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TintVectorTest, DoubleMoveAssign_WithSpill) {
|
TEST(TintVectorTest, RepeatMoveAssign_WithSpill) {
|
||||||
Vector<std::string, 1> vec_a{"hello", "world"};
|
Vector<std::string, 1> vec_a{"hello", "world"};
|
||||||
Vector<std::string, 1> vec_b{"Ciao", "mondo"};
|
Vector<std::string, 1> vec_b{"Ciao", "mondo"};
|
||||||
Vector<std::string, 1> vec_c{"bonjour", "le", "monde"};
|
Vector<std::string, 1> vec_c{"bonjour", "le", "monde"};
|
||||||
@ -816,6 +828,288 @@ TEST(TintVectorTest, DoubleMoveAssign_WithSpill) {
|
|||||||
EXPECT_TRUE(AllExternallyHeld(vec));
|
EXPECT_TRUE(AllExternallyHeld(vec));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, CopyAssignRef_NoSpill_N2_to_N2) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 2> vec_b;
|
||||||
|
vec_b = ref;
|
||||||
|
EXPECT_EQ(vec_b.Length(), 2u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 2u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_TRUE(AllInternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, CopyAssignRef_WithSpill_N2_to_N2) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world", "spill"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 2> vec_b;
|
||||||
|
vec_b = ref;
|
||||||
|
EXPECT_EQ(vec_b.Length(), 3u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 3u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_EQ(vec_b[2], "spill");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, CopyAssignRef_NoSpill_N2_to_N1) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 1> vec_b;
|
||||||
|
vec_b = ref;
|
||||||
|
EXPECT_EQ(vec_b.Length(), 2u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 2u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, CopyAssignRef_WithSpill_N2_to_N1) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world", "spill"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 1> vec_b;
|
||||||
|
vec_b = ref;
|
||||||
|
EXPECT_EQ(vec_b.Length(), 3u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 3u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_EQ(vec_b[2], "spill");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, CopyAssignRef_NoSpill_N2_to_N3) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 3> vec_b;
|
||||||
|
vec_b = ref;
|
||||||
|
EXPECT_EQ(vec_b.Length(), 2u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 3u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_TRUE(AllInternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, CopyAssignRef_WithSpill_N2_to_N3) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world", "spill"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 3> vec_b;
|
||||||
|
vec_b = ref;
|
||||||
|
EXPECT_EQ(vec_b.Length(), 3u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 3u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_EQ(vec_b[2], "spill");
|
||||||
|
EXPECT_TRUE(AllInternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, CopyAssignRef_NoSpill_N2_to_N0) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 0> vec_b;
|
||||||
|
vec_b = ref;
|
||||||
|
EXPECT_EQ(vec_b.Length(), 2u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 2u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, CopyAssignRef_WithSpill_N2_to_N0) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world", "spill"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 0> vec_b;
|
||||||
|
vec_b = ref;
|
||||||
|
EXPECT_EQ(vec_b.Length(), 3u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 3u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_EQ(vec_b[2], "spill");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, CopyAssignRef_Self_NoSpill) {
|
||||||
|
Vector<std::string, 2> vec{"hello", "world"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec)};
|
||||||
|
vec = ref;
|
||||||
|
EXPECT_EQ(vec.Length(), 2u);
|
||||||
|
EXPECT_EQ(vec.Capacity(), 2u);
|
||||||
|
EXPECT_EQ(vec[0], "hello");
|
||||||
|
EXPECT_EQ(vec[1], "world");
|
||||||
|
EXPECT_TRUE(AllInternallyHeld(vec));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, CopyAssignRef_Self_WithSpill) {
|
||||||
|
Vector<std::string, 1> vec{"hello", "world"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec)};
|
||||||
|
vec = ref;
|
||||||
|
EXPECT_EQ(vec.Length(), 2u);
|
||||||
|
EXPECT_EQ(vec.Capacity(), 2u);
|
||||||
|
EXPECT_EQ(vec[0], "hello");
|
||||||
|
EXPECT_EQ(vec[1], "world");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, MoveAssignRef_NoSpill_N2_to_N2) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 2> vec_b;
|
||||||
|
vec_b = std::move(ref);
|
||||||
|
EXPECT_EQ(vec_b.Length(), 2u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 2u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_TRUE(AllInternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, MoveAssignRef_WithSpill_N2_to_N2) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world", "spill"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 2> vec_b;
|
||||||
|
vec_b = std::move(ref);
|
||||||
|
EXPECT_EQ(vec_b.Length(), 3u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 3u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_EQ(vec_b[2], "spill");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, MoveAssignRef_NoSpill_N2_to_N1) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 1> vec_b;
|
||||||
|
vec_b = std::move(ref);
|
||||||
|
EXPECT_EQ(vec_b.Length(), 2u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 2u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, MoveAssignRef_SpillSpill_N2_to_N1) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world", "spill"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 1> vec_b;
|
||||||
|
vec_b = std::move(ref);
|
||||||
|
EXPECT_EQ(vec_b.Length(), 3u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 3u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_EQ(vec_b[2], "spill");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, MoveAssignRef_NoSpill_N2_to_N3) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 3> vec_b;
|
||||||
|
vec_b = std::move(ref);
|
||||||
|
EXPECT_EQ(vec_b.Length(), 2u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 3u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_TRUE(AllInternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, MoveAssignRef_WithSpill_N2_to_N3) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world", "spill"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 3> vec_b;
|
||||||
|
vec_b = std::move(ref);
|
||||||
|
EXPECT_EQ(vec_b.Length(), 3u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 3u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_EQ(vec_b[2], "spill");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, MoveAssignRef_NoSpill_N2_to_N0) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 0> vec_b;
|
||||||
|
vec_b = std::move(ref);
|
||||||
|
EXPECT_EQ(vec_b.Length(), 2u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 2u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, MoveAssignRef_WithSpill_N2_to_N0) {
|
||||||
|
Vector<std::string, 2> vec_a{"hello", "world", "spill"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec_a)};
|
||||||
|
Vector<std::string, 0> vec_b;
|
||||||
|
vec_b = std::move(ref);
|
||||||
|
EXPECT_EQ(vec_b.Length(), 3u);
|
||||||
|
EXPECT_EQ(vec_b.Capacity(), 3u);
|
||||||
|
EXPECT_EQ(vec_b[0], "hello");
|
||||||
|
EXPECT_EQ(vec_b[1], "world");
|
||||||
|
EXPECT_EQ(vec_b[2], "spill");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, MoveAssignRef_Self_NoSpill) {
|
||||||
|
Vector<std::string, 2> vec{"hello", "world"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec)};
|
||||||
|
vec = std::move(ref);
|
||||||
|
EXPECT_EQ(vec.Length(), 2u);
|
||||||
|
EXPECT_EQ(vec.Capacity(), 2u);
|
||||||
|
EXPECT_EQ(vec[0], "hello");
|
||||||
|
EXPECT_EQ(vec[1], "world");
|
||||||
|
EXPECT_TRUE(AllInternallyHeld(vec));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, MoveAssignRef_Self_WithSpill) {
|
||||||
|
Vector<std::string, 1> vec{"hello", "world"};
|
||||||
|
VectorRef<std::string> ref{std::move(vec)};
|
||||||
|
vec = std::move(ref);
|
||||||
|
EXPECT_EQ(vec.Length(), 2u);
|
||||||
|
EXPECT_EQ(vec.Capacity(), 2u);
|
||||||
|
EXPECT_EQ(vec[0], "hello");
|
||||||
|
EXPECT_EQ(vec[1], "world");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, RepeatMoveAssignRef_NoSpill) {
|
||||||
|
Vector<std::string, 3> vec_a{"hello", "world"};
|
||||||
|
Vector<std::string, 3> vec_b{"Ciao", "mondo"};
|
||||||
|
Vector<std::string, 3> vec_c{"Bonjour", "le", "monde"};
|
||||||
|
VectorRef<std::string> ref_a{std::move(vec_a)};
|
||||||
|
VectorRef<std::string> ref_b{std::move(vec_b)};
|
||||||
|
VectorRef<std::string> ref_c{std::move(vec_c)};
|
||||||
|
Vector<std::string, 3> vec;
|
||||||
|
vec = std::move(ref_a);
|
||||||
|
vec = std::move(ref_b);
|
||||||
|
vec = std::move(ref_c);
|
||||||
|
EXPECT_EQ(vec.Length(), 3u);
|
||||||
|
EXPECT_EQ(vec.Capacity(), 3u);
|
||||||
|
EXPECT_EQ(vec[0], "Bonjour");
|
||||||
|
EXPECT_EQ(vec[1], "le");
|
||||||
|
EXPECT_EQ(vec[2], "monde");
|
||||||
|
EXPECT_TRUE(AllInternallyHeld(vec));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TintVectorTest, RepeatMoveAssignRef_WithSpill) {
|
||||||
|
Vector<std::string, 1> vec_a{"hello", "world"};
|
||||||
|
Vector<std::string, 1> vec_b{"Ciao", "mondo"};
|
||||||
|
Vector<std::string, 1> vec_c{"bonjour", "le", "monde"};
|
||||||
|
VectorRef<std::string> ref_a{std::move(vec_a)};
|
||||||
|
VectorRef<std::string> ref_b{std::move(vec_b)};
|
||||||
|
VectorRef<std::string> ref_c{std::move(vec_c)};
|
||||||
|
Vector<std::string, 1> vec;
|
||||||
|
vec = std::move(ref_a);
|
||||||
|
vec = std::move(ref_b);
|
||||||
|
vec = std::move(ref_c);
|
||||||
|
EXPECT_EQ(vec.Length(), 3u);
|
||||||
|
EXPECT_EQ(vec.Capacity(), 3u);
|
||||||
|
EXPECT_EQ(vec[0], "bonjour");
|
||||||
|
EXPECT_EQ(vec[1], "le");
|
||||||
|
EXPECT_EQ(vec[2], "monde");
|
||||||
|
EXPECT_TRUE(AllExternallyHeld(vec));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(TintVectorTest, Index) {
|
TEST(TintVectorTest, Index) {
|
||||||
Vector<std::string, 2> vec{"hello", "world"};
|
Vector<std::string, 2> vec{"hello", "world"};
|
||||||
static_assert(!std::is_const_v<std::remove_reference_t<decltype(vec[0])>>);
|
static_assert(!std::is_const_v<std::remove_reference_t<decltype(vec[0])>>);
|
||||||
@ -1684,7 +1978,7 @@ TEST(TintVectorRefTest, MoveVector_UpcastAndAddConst) {
|
|||||||
TEST(TintVectorRefTest, Index) {
|
TEST(TintVectorRefTest, Index) {
|
||||||
Vector<std::string, 2> vec{"one", "two"};
|
Vector<std::string, 2> vec{"one", "two"};
|
||||||
VectorRef<std::string> vec_ref(vec);
|
VectorRef<std::string> vec_ref(vec);
|
||||||
static_assert(!std::is_const_v<std::remove_reference_t<decltype(vec_ref[0])>>);
|
static_assert(std::is_const_v<std::remove_reference_t<decltype(vec_ref[0])>>);
|
||||||
EXPECT_EQ(vec_ref[0], "one");
|
EXPECT_EQ(vec_ref[0], "one");
|
||||||
EXPECT_EQ(vec_ref[1], "two");
|
EXPECT_EQ(vec_ref[1], "two");
|
||||||
}
|
}
|
||||||
@ -1755,206 +2049,6 @@ TEST(TintVectorRefTest, ConstBeginEnd) {
|
|||||||
EXPECT_EQ(vec_ref.end(), &vec[0] + 3);
|
EXPECT_EQ(vec_ref.end(), &vec[0] + 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// TintVectorConstRefTest
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
TEST(TintVectorConstRefTest, CopyVectorConstRef) {
|
|
||||||
Vector<std::string, 1> vec_a{"one", "two"};
|
|
||||||
ConstVectorRef<std::string> vec_ref_a(vec_a);
|
|
||||||
ConstVectorRef<std::string> vec_ref_b(vec_ref_a);
|
|
||||||
Vector<std::string, 2> vec_b(vec_ref_b);
|
|
||||||
EXPECT_EQ(vec_b[0], "one");
|
|
||||||
EXPECT_EQ(vec_b[1], "two");
|
|
||||||
EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, CopyVectorConstRef_Upcast) {
|
|
||||||
C2a c2a;
|
|
||||||
C2b c2b;
|
|
||||||
Vector<C1*, 1> vec_a{&c2a, &c2b};
|
|
||||||
ConstVectorRef<C1*> vec_ref_a(vec_a);
|
|
||||||
ConstVectorRef<C0*> vec_ref_b(vec_ref_a); // Up-cast
|
|
||||||
Vector<C0*, 2> vec_b(vec_ref_b);
|
|
||||||
EXPECT_EQ(vec_b[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_b[1], &c2b);
|
|
||||||
EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, CopyVectorConstRef_AddConst) {
|
|
||||||
C2a c2a;
|
|
||||||
C2b c2b;
|
|
||||||
Vector<C1*, 1> vec_a{&c2a, &c2b};
|
|
||||||
ConstVectorRef<C1*> vec_ref_a(vec_a);
|
|
||||||
ConstVectorRef<const C1*> vec_ref_b(vec_ref_a); // Up-cast
|
|
||||||
Vector<const C1*, 2> vec_b(vec_ref_b);
|
|
||||||
EXPECT_EQ(vec_b[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_b[1], &c2b);
|
|
||||||
EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, CopyVectorConstRef_UpcastAndAddConst) {
|
|
||||||
C2a c2a;
|
|
||||||
C2b c2b;
|
|
||||||
Vector<C1*, 1> vec_a{&c2a, &c2b};
|
|
||||||
ConstVectorRef<C1*> vec_ref_a(vec_a);
|
|
||||||
ConstVectorRef<const C0*> vec_ref_b(vec_ref_a); // Up-cast
|
|
||||||
Vector<const C0*, 2> vec_b(vec_ref_b);
|
|
||||||
EXPECT_EQ(vec_b[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_b[1], &c2b);
|
|
||||||
EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, CopyVector) {
|
|
||||||
Vector<std::string, 1> vec_a{"one", "two"};
|
|
||||||
ConstVectorRef<std::string> vec_ref(vec_a);
|
|
||||||
Vector<std::string, 2> vec_b(vec_ref);
|
|
||||||
EXPECT_EQ(vec_b[0], "one");
|
|
||||||
EXPECT_EQ(vec_b[1], "two");
|
|
||||||
EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, CopyVector_Upcast) {
|
|
||||||
C2a c2a;
|
|
||||||
C2b c2b;
|
|
||||||
Vector<C1*, 1> vec_a{&c2a, &c2b};
|
|
||||||
ConstVectorRef<C0*> vec_ref(vec_a);
|
|
||||||
EXPECT_EQ(vec_ref[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_ref[1], &c2b);
|
|
||||||
Vector<C0*, 2> vec_b(vec_ref);
|
|
||||||
EXPECT_EQ(vec_b[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_b[1], &c2b);
|
|
||||||
EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, CopyVector_AddConst) {
|
|
||||||
C2a c2a;
|
|
||||||
C2b c2b;
|
|
||||||
Vector<C1*, 1> vec_a{&c2a, &c2b};
|
|
||||||
ConstVectorRef<const C1*> vec_ref(vec_a);
|
|
||||||
EXPECT_EQ(vec_ref[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_ref[1], &c2b);
|
|
||||||
Vector<const C1*, 2> vec_b(vec_ref);
|
|
||||||
EXPECT_EQ(vec_b[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_b[1], &c2b);
|
|
||||||
EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, CopyVectorRef_Upcast) {
|
|
||||||
C2a c2a;
|
|
||||||
C2b c2b;
|
|
||||||
Vector<C1*, 1> vec_a{&c2a, &c2b};
|
|
||||||
VectorRef<C1*> vec_ref_a(vec_a);
|
|
||||||
ConstVectorRef<C0*> vec_ref_b(vec_ref_a);
|
|
||||||
EXPECT_EQ(vec_ref_b[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_ref_b[1], &c2b);
|
|
||||||
Vector<C0*, 2> vec_b(vec_ref_b);
|
|
||||||
EXPECT_EQ(vec_b[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_b[1], &c2b);
|
|
||||||
EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, CopyVectorRef_AddConst) {
|
|
||||||
C2a c2a;
|
|
||||||
C2b c2b;
|
|
||||||
Vector<C1*, 1> vec_a{&c2a, &c2b};
|
|
||||||
VectorRef<C1*> vec_ref_a(vec_a);
|
|
||||||
ConstVectorRef<const C1*> vec_ref_b(vec_ref_a);
|
|
||||||
EXPECT_EQ(vec_ref_b[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_ref_b[1], &c2b);
|
|
||||||
Vector<const C1*, 2> vec_b(vec_ref_b);
|
|
||||||
EXPECT_EQ(vec_b[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_b[1], &c2b);
|
|
||||||
EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, CopyVectorRef_UpcastAndAddConst) {
|
|
||||||
C2a c2a;
|
|
||||||
C2b c2b;
|
|
||||||
Vector<C1*, 1> vec_a{&c2a, &c2b};
|
|
||||||
VectorRef<C1*> vec_ref_a(vec_a);
|
|
||||||
ConstVectorRef<const C0*> vec_ref_b(vec_ref_a);
|
|
||||||
EXPECT_EQ(vec_ref_b[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_ref_b[1], &c2b);
|
|
||||||
Vector<const C0*, 2> vec_b(vec_ref_b);
|
|
||||||
EXPECT_EQ(vec_b[0], &c2a);
|
|
||||||
EXPECT_EQ(vec_b[1], &c2b);
|
|
||||||
EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, Index) {
|
|
||||||
Vector<std::string, 2> vec{"one", "two"};
|
|
||||||
ConstVectorRef<std::string> vec_ref(vec);
|
|
||||||
static_assert(std::is_const_v<std::remove_reference_t<decltype(vec_ref[0])>>);
|
|
||||||
EXPECT_EQ(vec_ref[0], "one");
|
|
||||||
EXPECT_EQ(vec_ref[1], "two");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, ConstIndex) {
|
|
||||||
Vector<std::string, 2> vec{"one", "two"};
|
|
||||||
const ConstVectorRef<std::string> vec_ref(vec);
|
|
||||||
static_assert(std::is_const_v<std::remove_reference_t<decltype(vec_ref[0])>>);
|
|
||||||
EXPECT_EQ(vec_ref[0], "one");
|
|
||||||
EXPECT_EQ(vec_ref[1], "two");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, Length) {
|
|
||||||
Vector<std::string, 2> vec{"one", "two", "three"};
|
|
||||||
ConstVectorRef<std::string> vec_ref(vec);
|
|
||||||
EXPECT_EQ(vec_ref.Length(), 3u);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, Capacity) {
|
|
||||||
Vector<std::string, 5> vec{"one", "two", "three"};
|
|
||||||
ConstVectorRef<std::string> vec_ref(vec);
|
|
||||||
EXPECT_EQ(vec_ref.Capacity(), 5u);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, IsEmpty) {
|
|
||||||
Vector<std::string, 1> vec;
|
|
||||||
ConstVectorRef<std::string> vec_ref(vec);
|
|
||||||
EXPECT_TRUE(vec_ref.IsEmpty());
|
|
||||||
vec.Push("one");
|
|
||||||
EXPECT_FALSE(vec_ref.IsEmpty());
|
|
||||||
vec.Pop();
|
|
||||||
EXPECT_TRUE(vec_ref.IsEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, FrontBack) {
|
|
||||||
Vector<std::string, 3> vec{"front", "mid", "back"};
|
|
||||||
ConstVectorRef<std::string> vec_ref(vec);
|
|
||||||
static_assert(std::is_const_v<std::remove_reference_t<decltype(vec_ref.Front())>>);
|
|
||||||
static_assert(std::is_const_v<std::remove_reference_t<decltype(vec_ref.Back())>>);
|
|
||||||
EXPECT_EQ(vec_ref.Front(), "front");
|
|
||||||
EXPECT_EQ(vec_ref.Back(), "back");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, ConstFrontBack) {
|
|
||||||
Vector<std::string, 3> vec{"front", "mid", "back"};
|
|
||||||
const ConstVectorRef<std::string> vec_ref(vec);
|
|
||||||
static_assert(std::is_const_v<std::remove_reference_t<decltype(vec_ref.Front())>>);
|
|
||||||
static_assert(std::is_const_v<std::remove_reference_t<decltype(vec_ref.Back())>>);
|
|
||||||
EXPECT_EQ(vec_ref.Front(), "front");
|
|
||||||
EXPECT_EQ(vec_ref.Back(), "back");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, BeginEnd) {
|
|
||||||
Vector<std::string, 3> vec{"front", "mid", "back"};
|
|
||||||
ConstVectorRef<std::string> vec_ref(vec);
|
|
||||||
static_assert(std::is_const_v<std::remove_reference_t<decltype(*vec_ref.begin())>>);
|
|
||||||
static_assert(std::is_const_v<std::remove_reference_t<decltype(*vec_ref.end())>>);
|
|
||||||
EXPECT_EQ(vec_ref.begin(), &vec[0]);
|
|
||||||
EXPECT_EQ(vec_ref.end(), &vec[0] + 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TintVectorConstRefTest, ConstBeginEnd) {
|
|
||||||
Vector<std::string, 3> vec{"front", "mid", "back"};
|
|
||||||
const ConstVectorRef<std::string> vec_ref(vec);
|
|
||||||
static_assert(std::is_const_v<std::remove_reference_t<decltype(*vec_ref.begin())>>);
|
|
||||||
static_assert(std::is_const_v<std::remove_reference_t<decltype(*vec_ref.end())>>);
|
|
||||||
EXPECT_EQ(vec_ref.begin(), &vec[0]);
|
|
||||||
EXPECT_EQ(vec_ref.end(), &vec[0] + 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace tint::utils
|
} // namespace tint::utils
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user