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>
diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc
index 7bb7eb2..fe16221 100644
--- a/src/tint/resolver/builtin_test.cc
+++ b/src/tint/resolver/builtin_test.cc
@@ -2082,7 +2082,7 @@
testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
static std::string to_str(const std::string& function,
- utils::ConstVectorRef<const sem::Parameter*> params) {
+ utils::VectorRef<const sem::Parameter*> params) {
std::stringstream out;
out << function << "(";
bool first = true;
diff --git a/src/tint/resolver/const_eval.cc b/src/tint/resolver/const_eval.cc
index dec4992..71840a8 100644
--- a/src/tint/resolver/const_eval.cc
+++ b/src/tint/resolver/const_eval.cc
@@ -510,9 +510,8 @@
});
}
-const sem::Constant* ConstEval::ArrayOrStructCtor(
- const sem::Type* ty,
- utils::ConstVectorRef<const sem::Expression*> args) {
+const sem::Constant* ConstEval::ArrayOrStructCtor(const sem::Type* ty,
+ utils::VectorRef<const sem::Expression*> args) {
if (args.IsEmpty()) {
return ZeroValue(builder, ty);
}
@@ -532,7 +531,7 @@
}
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;
auto* el_ty = sem::Type::ElementOf(ty, &el_count);
if (!el_ty) {
@@ -553,17 +552,17 @@
}
const sem::Constant* ConstEval::Zero(const sem::Type* ty,
- utils::ConstVectorRef<const sem::Expression*>) {
+ utils::VectorRef<const sem::Expression*>) {
return ZeroValue(builder, ty);
}
const sem::Constant* ConstEval::Identity(const sem::Type*,
- utils::ConstVectorRef<const sem::Expression*> args) {
+ utils::VectorRef<const sem::Expression*> args) {
return args[0]->ConstantValue();
}
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()) {
return builder.create<Splat>(ty, arg, static_cast<const sem::Vector*>(ty)->Width());
}
@@ -571,7 +570,7 @@
}
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;
for (auto* arg : args) {
els.Push(arg->ConstantValue());
@@ -580,7 +579,7 @@
}
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;
for (auto* arg : args) {
auto* val = arg->ConstantValue();
@@ -605,7 +604,7 @@
}
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);
utils::Vector<const sem::Constant*, 4> els;
@@ -621,7 +620,7 @@
}
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;
for (auto* arg : args) {
els.Push(arg->ConstantValue());
@@ -668,7 +667,7 @@
const sem::Constant* ConstEval::Swizzle(const sem::Type* ty,
const sem::Expression* vec_expr,
- utils::ConstVectorRef<uint32_t> indices) {
+ utils::VectorRef<uint32_t> indices) {
auto* vec_val = vec_expr->ConstantValue();
if (!vec_val) {
return nullptr;
@@ -688,7 +687,7 @@
}
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 create = [&](auto i) {
return CreateElement(builder, c->Type(), decltype(i)(~i.value));
@@ -699,7 +698,7 @@
}
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 create = [&](auto i) { //
// For signed integrals, avoid C++ UB by not negating the
@@ -723,7 +722,7 @@
}
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 create = [&](auto i, auto j) {
return CreateElement(builder, c0->Type(), decltype(i)(std::atan2(i.value, j.value)));
@@ -735,7 +734,7 @@
}
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,
const sem::Constant* c2) {
auto create = [&](auto e, auto low, auto high) {
diff --git a/src/tint/resolver/const_eval.h b/src/tint/resolver/const_eval.h
index 4d299f4..5349637 100644
--- a/src/tint/resolver/const_eval.h
+++ b/src/tint/resolver/const_eval.h
@@ -45,8 +45,8 @@
class ConstEval {
public:
/// Typedef for a constant evaluation function
- using Function = const sem::Constant* (
- ConstEval::*)(const sem::Type* result_ty, utils::ConstVectorRef<const sem::Expression*>);
+ using Function = const sem::Constant* (ConstEval::*)(const sem::Type* result_ty,
+ utils::VectorRef<const sem::Expression*>);
/// 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:
@@ -71,7 +71,7 @@
/// @param args the input arguments
/// @return the constructed value, or null if the value cannot be calculated
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 expr the input expression
@@ -100,7 +100,7 @@
/// @return the result of the swizzle, or null if the value cannot be calculated
const sem::Constant* Swizzle(const sem::Type* ty,
const sem::Expression* vector,
- utils::ConstVectorRef<uint32_t> indices);
+ utils::VectorRef<uint32_t> indices);
/// Convert the `value` to `target_type`
/// @param ty the result type
@@ -117,57 +117,55 @@
/// @param ty the result type
/// @param args the input arguments
/// @return the converted value, or null if the value cannot be calculated
- const sem::Constant* Conv(const sem::Type* ty,
- utils::ConstVectorRef<const sem::Expression*> args);
+ const sem::Constant* Conv(const sem::Type* ty, utils::VectorRef<const sem::Expression*> args);
/// Zero value type constructor
/// @param ty the result type
/// @param args the input arguments (no arguments provided)
/// @return the constructed value, or null if the value cannot be calculated
- const sem::Constant* Zero(const sem::Type* ty,
- utils::ConstVectorRef<const sem::Expression*> args);
+ const sem::Constant* Zero(const sem::Type* ty, utils::VectorRef<const sem::Expression*> args);
/// Identity value type constructor
/// @param ty the result type
/// @param args the input arguments
/// @return the constructed value, or null if the value cannot be calculated
const sem::Constant* Identity(const sem::Type* ty,
- utils::ConstVectorRef<const sem::Expression*> args);
+ utils::VectorRef<const sem::Expression*> args);
/// Vector splat constructor
/// @param ty the vector type
/// @param args the input arguments
/// @return the constructed value, or null if the value cannot be calculated
const sem::Constant* VecSplat(const sem::Type* ty,
- utils::ConstVectorRef<const sem::Expression*> args);
+ utils::VectorRef<const sem::Expression*> args);
/// Vector constructor using scalars
/// @param ty the vector type
/// @param args the input arguments
/// @return the constructed value, or null if the value cannot be calculated
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
/// @param ty the vector type
/// @param args the input arguments
/// @return the constructed value, or null if the value cannot be calculated
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
/// @param ty the matrix type
/// @param args the input arguments
/// @return the constructed value, or null if the value cannot be calculated
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
/// @param ty the matrix type
/// @param args the input arguments
/// @return the constructed value, or null if the value cannot be calculated
const sem::Constant* MatCtorV(const sem::Type* ty,
- utils::ConstVectorRef<const sem::Expression*> args);
+ utils::VectorRef<const sem::Expression*> args);
////////////////////////////////////////////////////////////////////////////
// Operators
@@ -178,14 +176,14 @@
/// @param args the input arguments
/// @return the result value, or null if the value cannot be calculated
const sem::Constant* OpComplement(const sem::Type* ty,
- utils::ConstVectorRef<const sem::Expression*> args);
+ utils::VectorRef<const sem::Expression*> args);
/// Minus operator '-'
/// @param ty the expression type
/// @param args the input arguments
/// @return the result value, or null if the value cannot be calculated
const sem::Constant* OpMinus(const sem::Type* ty,
- utils::ConstVectorRef<const sem::Expression*> args);
+ utils::VectorRef<const sem::Expression*> args);
////////////////////////////////////////////////////////////////////////////
// Builtins
@@ -195,15 +193,13 @@
/// @param ty the expression type
/// @param args the input arguments
/// @return the result value, or null if the value cannot be calculated
- const sem::Constant* atan2(const sem::Type* ty,
- utils::ConstVectorRef<const sem::Expression*> args);
+ const sem::Constant* atan2(const sem::Type* ty, utils::VectorRef<const sem::Expression*> args);
/// clamp builtin
/// @param ty the expression type
/// @param args the input arguments
/// @return the result value, or null if the value cannot be calculated
- const sem::Constant* clamp(const sem::Type* ty,
- utils::ConstVectorRef<const sem::Expression*> args);
+ const sem::Constant* clamp(const sem::Type* ty, utils::VectorRef<const sem::Expression*> args);
private:
/// Adds the given error message to the diagnostics
diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc
index bb5791f..57c60b0 100644
--- a/src/tint/resolver/intrinsic_table.cc
+++ b/src/tint/resolver/intrinsic_table.cc
@@ -1026,14 +1026,14 @@
// Prints the list of candidates for emitting diagnostics
void PrintCandidates(std::ostream& ss,
- utils::ConstVectorRef<Candidate> candidates,
+ utils::VectorRef<Candidate> candidates,
const char* intrinsic_name) const;
/// Raises an error when no overload is a clear winner of overload resolution
void ErrAmbiguousOverload(const char* intrinsic_name,
- utils::ConstVectorRef<const sem::Type*> args,
+ utils::VectorRef<const sem::Type*> args,
TemplateState templates,
- utils::ConstVectorRef<Candidate> candidates) const;
+ utils::VectorRef<Candidate> candidates) const;
ProgramBuilder& builder;
Matchers matchers;
@@ -1604,7 +1604,7 @@
}
void Impl::PrintCandidates(std::ostream& ss,
- utils::ConstVectorRef<Candidate> candidates,
+ utils::VectorRef<Candidate> candidates,
const char* intrinsic_name) const {
for (auto& candidate : candidates) {
ss << " ";
@@ -1638,9 +1638,9 @@
}
void Impl::ErrAmbiguousOverload(const char* intrinsic_name,
- utils::ConstVectorRef<const sem::Type*> args,
+ utils::VectorRef<const sem::Type*> args,
TemplateState templates,
- utils::ConstVectorRef<Candidate> candidates) const {
+ utils::VectorRef<Candidate> candidates) const {
std::stringstream ss;
ss << "ambiguous overload while attempting to match " << intrinsic_name;
for (size_t i = 0; i < std::numeric_limits<size_t>::max(); i++) {
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index e5d4c65..8f85398 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -1406,7 +1406,8 @@
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) {
for (size_t i = 0, n = std::min(args.Length(), target->Parameters().Length()); i < n; i++) {
const auto* param_ty = target->Parameters()[i]->Type();
@@ -1778,9 +1779,7 @@
// there's no need to infer element types.
return ty_ctor_or_conv(ty);
},
- [&](sem::Function* func) {
- return FunctionCall(expr, func, std::move(args), arg_behaviors);
- },
+ [&](sem::Function* func) { return FunctionCall(expr, func, args, arg_behaviors); },
[&](sem::Variable* var) {
auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
AddError("cannot call variable '" + name + "'", ident->source);
@@ -1791,7 +1790,7 @@
auto name = builder_->Symbols().NameFor(ident->symbol);
auto builtin_type = sem::ParseBuiltinType(name);
if (builtin_type != sem::BuiltinType::kNone) {
- return BuiltinCall(expr, builtin_type, std::move(args));
+ return BuiltinCall(expr, builtin_type, args);
}
TINT_ICE(Resolver, diagnostics_)
@@ -1809,12 +1808,13 @@
return validator_.Call(call, current_statement_) ? call : nullptr;
}
+template <size_t N>
sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
sem::BuiltinType builtin_type,
- utils::VectorRef<const sem::Expression*> args) {
+ utils::Vector<const sem::Expression*, N>& args) {
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);
if (!builtin.sem) {
return nullptr;
@@ -1876,9 +1876,8 @@
return call;
}
-void Resolver::CollectTextureSamplerPairs(
- const sem::Builtin* builtin,
- utils::ConstVectorRef<const sem::Expression*> args) const {
+void Resolver::CollectTextureSamplerPairs(const sem::Builtin* builtin,
+ utils::VectorRef<const sem::Expression*> args) const {
// Collect a texture/sampler pair for this builtin.
const auto& signature = builtin->Signature();
int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
@@ -1896,9 +1895,10 @@
}
}
+template <size_t N>
sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr,
sem::Function* target,
- utils::VectorRef<const sem::Expression*> args,
+ utils::Vector<const sem::Expression*, N>& args,
sem::Behaviors arg_behaviors) {
auto sym = expr->target.name->symbol;
auto name = builder_->Symbols().NameFor(sym);
@@ -1944,9 +1944,8 @@
return call;
}
-void Resolver::CollectTextureSamplerPairs(
- sem::Function* func,
- utils::ConstVectorRef<const sem::Expression*> args) const {
+void Resolver::CollectTextureSamplerPairs(sem::Function* func,
+ utils::VectorRef<const sem::Expression*> args) const {
// Map all texture/sampler pairs from the target function to the
// current function. These can only be global or parameter
// variables. Resolve any parameter variables to the corresponding
diff --git a/src/tint/resolver/resolver.h b/src/tint/resolver/resolver.h
index fa5a569..ecbda30 100644
--- a/src/tint/resolver/resolver.h
+++ b/src/tint/resolver/resolver.h
@@ -193,14 +193,16 @@
sem::Expression* Bitcast(const ast::BitcastExpression*);
sem::Call* Call(const ast::CallExpression*);
sem::Function* Function(const ast::Function*);
+ template <size_t N>
sem::Call* FunctionCall(const ast::CallExpression*,
sem::Function* target,
- utils::VectorRef<const sem::Expression*> args,
+ utils::Vector<const sem::Expression*, N>& args,
sem::Behaviors arg_behaviors);
sem::Expression* Identifier(const ast::IdentifierExpression*);
+ template <size_t N>
sem::Call* BuiltinCall(const ast::CallExpression*,
sem::BuiltinType,
- utils::VectorRef<const sem::Expression*> args);
+ utils::Vector<const sem::Expression*, N>& args);
sem::Expression* Literal(const ast::LiteralExpression*);
sem::Expression* MemberAccessor(const ast::MemberAccessorExpression*);
sem::Expression* UnaryOp(const ast::UnaryOpExpression*);
@@ -223,7 +225,8 @@
/// Materializes all the arguments in `args` to the parameter types of `target`.
/// @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);
/// @returns true if an argument of an abstract numeric type, passed to a parameter of type
@@ -267,9 +270,9 @@
// CollectTextureSamplerPairs() collects all the texture/sampler pairs from the target function
// / builtin, and records these on the current function by calling AddTextureSamplerPair().
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,
- utils::ConstVectorRef<const sem::Expression*> args) const;
+ utils::VectorRef<const sem::Expression*> args) const;
/// Resolves the WorkgroupSize for the given function, assigning it to
/// current_function_
diff --git a/src/tint/sem/type.cc b/src/tint/sem/type.cc
index fcc1654..b4887dd 100644
--- a/src/tint/sem/type.cc
+++ b/src/tint/sem/type.cc
@@ -272,7 +272,7 @@
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();
if (count == 0) {
return nullptr;
diff --git a/src/tint/sem/type.h b/src/tint/sem/type.h
index c2b83e5..8bac821c 100644
--- a/src/tint/sem/type.h
+++ b/src/tint/sem/type.h
@@ -161,7 +161,7 @@
/// @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`.
/// @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:
Type();
diff --git a/src/tint/utils/transform.h b/src/tint/utils/transform.h
index 412dbed..2faca46 100644
--- a/src/tint/utils/transform.h
+++ b/src/tint/utils/transform.h
@@ -119,40 +119,6 @@
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
/// most `n` elements.
/// @param in the input vector.
diff --git a/src/tint/utils/transform_test.cc b/src/tint/utils/transform_test.cc
index 656b827..71b3f0c 100644
--- a/src/tint/utils/transform_test.cc
+++ b/src/tint/utils/transform_test.cc
@@ -345,72 +345,5 @@
}
}
-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 tint::utils
diff --git a/src/tint/utils/vector.h b/src/tint/utils/vector.h
index d339a49..ee305e2 100644
--- a/src/tint/utils/vector.h
+++ b/src/tint/utils/vector.h
@@ -32,12 +32,18 @@
template <typename>
class VectorRef;
template <typename>
-class ConstVectorRef;
+class VectorRef;
} // 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.
template <typename T>
struct Slice {
@@ -165,6 +171,9 @@
Vector() = default;
/// Constructor
+ Vector(EmptyType) {} // NOLINT(runtime/explicit)
+
+ /// Constructor
/// @param elements the elements to place into the vector
Vector(std::initializer_list<T> elements) {
Reserve(elements.size());
@@ -217,10 +226,7 @@
/// Copy constructor from an immutable vector reference
/// @param other the vector reference to copy
- explicit Vector(const ConstVectorRef<T>& other) { Copy(other.slice_); }
-
- /// Move constructor from an immutable vector reference (invalid)
- Vector(ConstVectorRef<T>&&) = delete; // NOLINT(runtime/explicit)
+ explicit Vector(const VectorRef<T>& other) { Copy(other.slice_); }
/// Destructor
~Vector() { ClearAndFree(); }
@@ -263,6 +269,26 @@
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
/// @param i the element index. Must be less than `len`.
/// @returns a reference to the i'th element.
@@ -367,7 +393,12 @@
/// Removes and returns the last element from the vector.
/// @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.
bool IsEmpty() const { return impl_.slice.len == 0; }
@@ -419,7 +450,7 @@
/// Friend class
template <typename>
- friend class ConstVectorRef;
+ friend class VectorRef;
/// The slice type used by this vector
using Slice = utils::Slice<T>;
@@ -573,11 +604,10 @@
/// 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
-/// 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 parameter, and within the callee, the VectorRef parameter is
-/// moved to a Vector, then the Vector heap allocation will be moved. For example:
+/// 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
+/// parameter, and within the callee, the VectorRef parameter is moved to a Vector, then the Vector
+/// heap allocation will be moved. For example:
///
/// ```
/// void func_a() {
@@ -596,12 +626,30 @@
/// The slice type used by this vector reference
using Slice = utils::Slice<T>;
+ /// @returns an empty slice.
+ static Slice& EmptySlice() {
+ static Slice empty;
+ return empty;
+ }
+
public:
+ /// Constructor - empty reference
+ VectorRef() : slice_(EmptySlice()) {}
+
+ /// Constructor
+ VectorRef(EmptyType) : slice_(EmptySlice()) {} // NOLINT(runtime/explicit)
+
/// Constructor from a Vector
/// @param vector the vector to create a reference of
template <size_t N>
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
/// @param vector the vector being moved
@@ -611,7 +659,7 @@
/// Copy constructor
/// @param other the vector reference
- VectorRef(const VectorRef& other) : slice_(other.slice_), can_move_(false) {}
+ VectorRef(const VectorRef& other) : slice_(other.slice_) {}
/// Move constructor
/// @param other the vector reference
@@ -621,7 +669,7 @@
/// @param other the other vector reference
template <typename U, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
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
/// @param other the vector reference
@@ -634,7 +682,7 @@
/// @see CanReinterpretSlice for rules about conversion
template <typename U, size_t N, typename = std::enable_if_t<CanReinterpretSlice<T, U>>>
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
/// @param vector the vector to create a reference of
@@ -646,11 +694,6 @@
/// 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
- /// @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
@@ -710,7 +753,7 @@
/// Friend class
template <typename>
- friend class ConstVectorRef;
+ friend class VectorRef;
/// The slice of the vector being referenced.
Slice& slice_;
@@ -718,99 +761,6 @@
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.
/// @note This helper exists to help code migration. Avoid if possible.
template <typename T, size_t N>
diff --git a/src/tint/utils/vector_test.cc b/src/tint/utils/vector_test.cc
index 6e529dc..24cfcbe 100644
--- a/src/tint/utils/vector_test.cc
+++ b/src/tint/utils/vector_test.cc
@@ -105,12 +105,24 @@
EXPECT_EQ(vec.Capacity(), 2u);
}
-TEST(TintVectorTest, Empty_NoSmallArray) {
+TEST(TintVectorTest, NoSmallArray) {
Vector<int, 0> vec;
EXPECT_EQ(vec.Length(), 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) {
Vector<std::string, 2> vec{"one", "two"};
EXPECT_EQ(vec.Length(), 2u);
@@ -800,7 +812,7 @@
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_b{"Ciao", "mondo"};
Vector<std::string, 1> vec_c{"bonjour", "le", "monde"};
@@ -816,6 +828,288 @@
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) {
Vector<std::string, 2> vec{"hello", "world"};
static_assert(!std::is_const_v<std::remove_reference_t<decltype(vec[0])>>);
@@ -1684,7 +1978,7 @@
TEST(TintVectorRefTest, Index) {
Vector<std::string, 2> vec{"one", "two"};
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[1], "two");
}
@@ -1755,206 +2049,6 @@
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 tint::utils