diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc index 7bb7eb23ca..fe1622112c 100644 --- a/src/tint/resolver/builtin_test.cc +++ b/src/tint/resolver/builtin_test.cc @@ -2082,7 +2082,7 @@ INSTANTIATE_TEST_SUITE_P(ResolverTest, testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases())); static std::string to_str(const std::string& function, - utils::ConstVectorRef params) { + utils::VectorRef 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 dec4992527..71840a880a 100644 --- a/src/tint/resolver/const_eval.cc +++ b/src/tint/resolver/const_eval.cc @@ -510,9 +510,8 @@ const sem::Constant* ConstEval::Literal(const sem::Type* ty, }); } -const sem::Constant* ConstEval::ArrayOrStructCtor( - const sem::Type* ty, - utils::ConstVectorRef args) { +const sem::Constant* ConstEval::ArrayOrStructCtor(const sem::Type* ty, + utils::VectorRef args) { if (args.IsEmpty()) { return ZeroValue(builder, ty); } @@ -532,7 +531,7 @@ const sem::Constant* ConstEval::ArrayOrStructCtor( } const sem::Constant* ConstEval::Conv(const sem::Type* ty, - utils::ConstVectorRef args) { + utils::VectorRef 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::Conv(const sem::Type* ty, } const sem::Constant* ConstEval::Zero(const sem::Type* ty, - utils::ConstVectorRef) { + utils::VectorRef) { return ZeroValue(builder, ty); } const sem::Constant* ConstEval::Identity(const sem::Type*, - utils::ConstVectorRef args) { + utils::VectorRef args) { return args[0]->ConstantValue(); } const sem::Constant* ConstEval::VecSplat(const sem::Type* ty, - utils::ConstVectorRef args) { + utils::VectorRef args) { if (auto* arg = args[0]->ConstantValue()) { return builder.create(ty, arg, static_cast(ty)->Width()); } @@ -571,7 +570,7 @@ const sem::Constant* ConstEval::VecSplat(const sem::Type* ty, } const sem::Constant* ConstEval::VecCtorS(const sem::Type* ty, - utils::ConstVectorRef args) { + utils::VectorRef args) { utils::Vector els; for (auto* arg : args) { 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, - utils::ConstVectorRef args) { + utils::VectorRef args) { utils::Vector els; for (auto* arg : args) { 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, - utils::ConstVectorRef args) { + utils::VectorRef args) { auto* m = static_cast(ty); utils::Vector els; @@ -621,7 +620,7 @@ const sem::Constant* ConstEval::MatCtorS(const sem::Type* ty, } const sem::Constant* ConstEval::MatCtorV(const sem::Type* ty, - utils::ConstVectorRef args) { + utils::VectorRef args) { utils::Vector els; for (auto* arg : args) { 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::Expression* vec_expr, - utils::ConstVectorRef indices) { + utils::VectorRef indices) { auto* vec_val = vec_expr->ConstantValue(); if (!vec_val) { 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*, - utils::ConstVectorRef args) { + utils::VectorRef 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::OpComplement(const sem::Type*, } const sem::Constant* ConstEval::OpMinus(const sem::Type*, - utils::ConstVectorRef args) { + utils::VectorRef 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::OpMinus(const sem::Type*, } const sem::Constant* ConstEval::atan2(const sem::Type*, - utils::ConstVectorRef args) { + utils::VectorRef 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::atan2(const sem::Type*, } const sem::Constant* ConstEval::clamp(const sem::Type*, - utils::ConstVectorRef args) { + utils::VectorRef 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 4d299f4ea8..5349637865 100644 --- a/src/tint/resolver/const_eval.h +++ b/src/tint/resolver/const_eval.h @@ -45,8 +45,8 @@ namespace tint::resolver { class ConstEval { public: /// Typedef for a constant evaluation function - using Function = const sem::Constant* ( - ConstEval::*)(const sem::Type* result_ty, utils::ConstVectorRef); + using Function = const sem::Constant* (ConstEval::*)(const sem::Type* result_ty, + utils::VectorRef); /// 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 @@ class ConstEval { /// @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 args); + utils::VectorRef args); /// @param ty the target type /// @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 const sem::Constant* Swizzle(const sem::Type* ty, const sem::Expression* vector, - utils::ConstVectorRef indices); + utils::VectorRef indices); /// Convert the `value` to `target_type` /// @param ty the result type @@ -117,57 +117,55 @@ class ConstEval { /// @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 args); + const sem::Constant* Conv(const sem::Type* ty, utils::VectorRef 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 args); + const sem::Constant* Zero(const sem::Type* ty, utils::VectorRef 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 args); + utils::VectorRef 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 args); + utils::VectorRef 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 args); + utils::VectorRef 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 args); + utils::VectorRef 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 args); + utils::VectorRef 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 args); + utils::VectorRef args); //////////////////////////////////////////////////////////////////////////// // Operators @@ -178,14 +176,14 @@ class ConstEval { /// @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 args); + utils::VectorRef 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 args); + utils::VectorRef args); //////////////////////////////////////////////////////////////////////////// // Builtins @@ -195,15 +193,13 @@ class ConstEval { /// @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 args); + const sem::Constant* atan2(const sem::Type* ty, utils::VectorRef 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 args); + const sem::Constant* clamp(const sem::Type* ty, utils::VectorRef 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 bb5791f45b..57c60b0d92 100644 --- a/src/tint/resolver/intrinsic_table.cc +++ b/src/tint/resolver/intrinsic_table.cc @@ -1026,14 +1026,14 @@ class Impl : public IntrinsicTable { // Prints the list of candidates for emitting diagnostics void PrintCandidates(std::ostream& ss, - utils::ConstVectorRef candidates, + utils::VectorRef 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 args, + utils::VectorRef args, TemplateState templates, - utils::ConstVectorRef candidates) const; + utils::VectorRef candidates) const; ProgramBuilder& builder; Matchers matchers; @@ -1604,7 +1604,7 @@ void Impl::PrintOverload(std::ostream& ss, } void Impl::PrintCandidates(std::ostream& ss, - utils::ConstVectorRef candidates, + utils::VectorRef candidates, const char* intrinsic_name) const { for (auto& candidate : candidates) { ss << " "; @@ -1638,9 +1638,9 @@ std::string MatchState::NumName() { } void Impl::ErrAmbiguousOverload(const char* intrinsic_name, - utils::ConstVectorRef args, + utils::VectorRef args, TemplateState templates, - utils::ConstVectorRef candidates) const { + utils::VectorRef candidates) const { std::stringstream ss; ss << "ambiguous overload while attempting to match " << intrinsic_name; for (size_t i = 0; i < std::numeric_limits::max(); i++) { diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc index e5d4c6589f..8f85398f97 100644 --- a/src/tint/resolver/resolver.cc +++ b/src/tint/resolver/resolver.cc @@ -1406,7 +1406,8 @@ const sem::Expression* Resolver::Materialize(const sem::Expression* expr, return m; } -bool Resolver::MaterializeArguments(utils::VectorRef args, +template +bool Resolver::MaterializeArguments(utils::Vector& 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 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) { // 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 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) { 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 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) { return validator_.Call(call, current_statement_) ? call : nullptr; } +template sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr, sem::BuiltinType builtin_type, - utils::VectorRef args) { + utils::Vector& 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 @@ sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr, return call; } -void Resolver::CollectTextureSamplerPairs( - const sem::Builtin* builtin, - utils::ConstVectorRef args) const { +void Resolver::CollectTextureSamplerPairs(const sem::Builtin* builtin, + utils::VectorRef 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 @@ void Resolver::CollectTextureSamplerPairs( } } +template sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr, sem::Function* target, - utils::VectorRef args, + utils::Vector& args, sem::Behaviors arg_behaviors) { auto sym = expr->target.name->symbol; auto name = builder_->Symbols().NameFor(sym); @@ -1944,9 +1944,8 @@ sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr, return call; } -void Resolver::CollectTextureSamplerPairs( - sem::Function* func, - utils::ConstVectorRef args) const { +void Resolver::CollectTextureSamplerPairs(sem::Function* func, + utils::VectorRef 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 fa5a569cfc..ecbda3042f 100644 --- a/src/tint/resolver/resolver.h +++ b/src/tint/resolver/resolver.h @@ -193,14 +193,16 @@ class Resolver { sem::Expression* Bitcast(const ast::BitcastExpression*); sem::Call* Call(const ast::CallExpression*); sem::Function* Function(const ast::Function*); + template sem::Call* FunctionCall(const ast::CallExpression*, sem::Function* target, - utils::VectorRef args, + utils::Vector& args, sem::Behaviors arg_behaviors); sem::Expression* Identifier(const ast::IdentifierExpression*); + template sem::Call* BuiltinCall(const ast::CallExpression*, sem::BuiltinType, - utils::VectorRef args); + utils::Vector& args); sem::Expression* Literal(const ast::LiteralExpression*); sem::Expression* MemberAccessor(const ast::MemberAccessorExpression*); sem::Expression* UnaryOp(const ast::UnaryOpExpression*); @@ -223,7 +225,8 @@ class Resolver { /// Materializes all the arguments in `args` to the parameter types of `target`. /// @returns true on success, false on failure. - bool MaterializeArguments(utils::VectorRef args, + template + bool MaterializeArguments(utils::Vector& 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 @@ class Resolver { // 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 args) const; + utils::VectorRef args) const; void CollectTextureSamplerPairs(const sem::Builtin* builtin, - utils::ConstVectorRef args) const; + utils::VectorRef 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 fcc16544e3..b4887dd90e 100644 --- a/src/tint/sem/type.cc +++ b/src/tint/sem/type.cc @@ -272,7 +272,7 @@ const Type* Type::DeepestElementOf(const Type* ty, uint32_t* count /* = nullptr return el_ty; } -const sem::Type* Type::Common(utils::ConstVectorRef types) { +const sem::Type* Type::Common(utils::VectorRef 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 c2b83e50dc..8bac821ca4 100644 --- a/src/tint/sem/type.h +++ b/src/tint/sem/type.h @@ -161,7 +161,7 @@ class Type : public Castable { /// @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 types); + static const sem::Type* Common(utils::VectorRef types); protected: Type(); diff --git a/src/tint/utils/transform.h b/src/tint/utils/transform.h index 412dbed3cb..2faca462c1 100644 --- a/src/tint/utils/transform.h +++ b/src/tint/utils/transform.h @@ -119,40 +119,6 @@ auto Transform(const VectorRef& in, TRANSFORMER&& transform) 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 -auto Transform(ConstVectorRef in, TRANSFORMER&& transform) - -> Vector { - const auto count = in.Length(); - Vector 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 -auto Transform(ConstVectorRef in, TRANSFORMER&& transform) - -> Vector { - const auto count = in.Length(); - Vector 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 656b827f2b..71b3f0cb51 100644 --- a/src/tint/utils/transform_test.cc +++ b/src/tint/utils/transform_test.cc @@ -345,72 +345,5 @@ TEST(TransformTest, TransformVectorRefDifferentType) { } } -TEST(TransformTest, ConstVectorRefEmpty) { - const Vector empty{}; - ConstVectorRef 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 input{1, 2, 3, 4}; - ConstVectorRef 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 input{1, 2, 3, 4}; - ConstVectorRef 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 input{10, 20, 30, 40}; - ConstVectorRef 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 input{1, 2, 3, 4}; - ConstVectorRef 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 input{1, 2, 3, 4}; - ConstVectorRef 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 d339a49714..ee305e25dd 100644 --- a/src/tint/utils/vector.h +++ b/src/tint/utils/vector.h @@ -32,12 +32,18 @@ namespace tint::utils { template class VectorRef; template -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 struct Slice { @@ -164,6 +170,9 @@ class Vector { /// Constructor Vector() = default; + /// Constructor + Vector(EmptyType) {} // NOLINT(runtime/explicit) + /// Constructor /// @param elements the elements to place into the vector Vector(std::initializer_list elements) { @@ -217,10 +226,7 @@ class Vector { /// Copy constructor from an immutable vector reference /// @param other the vector reference to copy - explicit Vector(const ConstVectorRef& other) { Copy(other.slice_); } - - /// Move constructor from an immutable vector reference (invalid) - Vector(ConstVectorRef&&) = delete; // NOLINT(runtime/explicit) + explicit Vector(const VectorRef& other) { Copy(other.slice_); } /// Destructor ~Vector() { ClearAndFree(); } @@ -263,6 +269,26 @@ class Vector { 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& 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&& 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 @@ class Vector { /// 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 @@ class Vector { /// Friend class template - friend class ConstVectorRef; + friend class VectorRef; /// The slice type used by this vector using Slice = utils::Slice; @@ -573,11 +604,10 @@ Vector(Ts...) -> Vector, sizeof...(Ts)>; /// 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 @@ class VectorRef { /// The slice type used by this vector reference using Slice = utils::Slice; + /// @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 VectorRef(Vector& 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 + VectorRef(const Vector& vector) // NOLINT(runtime/explicit) + : slice_(const_cast(vector.impl_.slice)) {} /// Constructor from a moved Vector /// @param vector the vector being moved @@ -611,7 +659,7 @@ class VectorRef { /// 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 @@ class VectorRef { /// @param other the other vector reference template >> VectorRef(const VectorRef& other) // NOLINT(runtime/explicit) - : slice_(*ReinterpretSlice(&other.slice_)), can_move_(false) {} + : slice_(*ReinterpretSlice(&other.slice_)) {} /// Move constructor with covariance / const conversion /// @param other the vector reference @@ -634,7 +682,7 @@ class VectorRef { /// @see CanReinterpretSlice for rules about conversion template >> VectorRef(Vector& vector) // NOLINT(runtime/explicit) - : slice_(*ReinterpretSlice(&vector.impl_.slice)), can_move_(false) {} + : slice_(*ReinterpretSlice(&vector.impl_.slice)) {} /// Constructor from a moved Vector with covariance / const conversion /// @param vector the vector to create a reference of @@ -643,11 +691,6 @@ class VectorRef { VectorRef(Vector&& vector) // NOLINT(runtime/explicit) : slice_(*ReinterpretSlice(&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 /// @param i the element index. Must be less than `len`. /// @returns a reference to the i'th element. @@ -710,7 +753,7 @@ class VectorRef { /// Friend class template - friend class ConstVectorRef; + friend class VectorRef; /// The slice of the vector being referenced. Slice& slice_; @@ -718,99 +761,6 @@ class VectorRef { 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 -class ConstVectorRef { - /// The slice type used by this vector reference - using Slice = utils::Slice; - - public: - /// Constructor from a Vector. - /// @param vector the vector reference - template - ConstVectorRef(const Vector& 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& 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 >> - ConstVectorRef(const Vector& vector) // NOLINT(runtime/explicit) - : slice_(*ReinterpretSlice(&vector.impl_.slice)) {} - - /// Constructor from a VectorRef with covariance / const conversion - /// @param other the vector reference - /// @see CanReinterpretSlice for rules about conversion - template >> - ConstVectorRef(const VectorRef& other) // NOLINT(runtime/explicit) - : slice_(*ReinterpretSlice(&other.slice_)) {} - - /// Constructor from a ConstVectorRef with covariance / const conversion - /// @param other the vector reference - /// @see CanReinterpretSlice for rules about conversion - template >> - ConstVectorRef(const ConstVectorRef& other) // NOLINT(runtime/explicit) - : slice_(*ReinterpretSlice(&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 - friend class Vector; - - /// Friend class - template - 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 diff --git a/src/tint/utils/vector_test.cc b/src/tint/utils/vector_test.cc index 6e529dc697..24cfcbe43f 100644 --- a/src/tint/utils/vector_test.cc +++ b/src/tint/utils/vector_test.cc @@ -105,12 +105,24 @@ TEST(TintVectorTest, SmallArray_Empty) { EXPECT_EQ(vec.Capacity(), 2u); } -TEST(TintVectorTest, Empty_NoSmallArray) { +TEST(TintVectorTest, NoSmallArray) { Vector vec; EXPECT_EQ(vec.Length(), 0u); EXPECT_EQ(vec.Capacity(), 0u); } +TEST(TintVectorTest, Empty_SmallArray_Empty) { + Vector vec(Empty); + EXPECT_EQ(vec.Length(), 0u); + EXPECT_EQ(vec.Capacity(), 2u); +} + +TEST(TintVectorTest, Empty_NoSmallArray) { + Vector vec(Empty); + EXPECT_EQ(vec.Length(), 0u); + EXPECT_EQ(vec.Capacity(), 0u); +} + TEST(TintVectorTest, InitializerList_NoSpill) { Vector vec{"one", "two"}; EXPECT_EQ(vec.Length(), 2u); @@ -800,7 +812,7 @@ TEST(TintVectorTest, RepeatMoveAssign_NoSpill) { EXPECT_TRUE(AllInternallyHeld(vec)); } -TEST(TintVectorTest, DoubleMoveAssign_WithSpill) { +TEST(TintVectorTest, RepeatMoveAssign_WithSpill) { Vector vec_a{"hello", "world"}; Vector vec_b{"Ciao", "mondo"}; Vector vec_c{"bonjour", "le", "monde"}; @@ -816,6 +828,288 @@ TEST(TintVectorTest, DoubleMoveAssign_WithSpill) { EXPECT_TRUE(AllExternallyHeld(vec)); } +TEST(TintVectorTest, CopyAssignRef_NoSpill_N2_to_N2) { + Vector vec_a{"hello", "world"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world", "spill"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world", "spill"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world", "spill"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world", "spill"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec{"hello", "world"}; + VectorRef 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 vec{"hello", "world"}; + VectorRef 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 vec_a{"hello", "world"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world", "spill"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world", "spill"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world", "spill"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec_a{"hello", "world", "spill"}; + VectorRef ref{std::move(vec_a)}; + Vector 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 vec{"hello", "world"}; + VectorRef 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 vec{"hello", "world"}; + VectorRef 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 vec_a{"hello", "world"}; + Vector vec_b{"Ciao", "mondo"}; + Vector vec_c{"Bonjour", "le", "monde"}; + VectorRef ref_a{std::move(vec_a)}; + VectorRef ref_b{std::move(vec_b)}; + VectorRef ref_c{std::move(vec_c)}; + Vector 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 vec_a{"hello", "world"}; + Vector vec_b{"Ciao", "mondo"}; + Vector vec_c{"bonjour", "le", "monde"}; + VectorRef ref_a{std::move(vec_a)}; + VectorRef ref_b{std::move(vec_b)}; + VectorRef ref_c{std::move(vec_c)}; + Vector 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 vec{"hello", "world"}; static_assert(!std::is_const_v>); @@ -1684,7 +1978,7 @@ TEST(TintVectorRefTest, MoveVector_UpcastAndAddConst) { TEST(TintVectorRefTest, Index) { Vector vec{"one", "two"}; VectorRef vec_ref(vec); - static_assert(!std::is_const_v>); + static_assert(std::is_const_v>); EXPECT_EQ(vec_ref[0], "one"); EXPECT_EQ(vec_ref[1], "two"); } @@ -1755,206 +2049,6 @@ TEST(TintVectorRefTest, ConstBeginEnd) { EXPECT_EQ(vec_ref.end(), &vec[0] + 3); } -//////////////////////////////////////////////////////////////////////////////// -// TintVectorConstRefTest -//////////////////////////////////////////////////////////////////////////////// -TEST(TintVectorConstRefTest, CopyVectorConstRef) { - Vector vec_a{"one", "two"}; - ConstVectorRef vec_ref_a(vec_a); - ConstVectorRef vec_ref_b(vec_ref_a); - Vector 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 vec_a{&c2a, &c2b}; - ConstVectorRef vec_ref_a(vec_a); - ConstVectorRef vec_ref_b(vec_ref_a); // Up-cast - Vector 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 vec_a{&c2a, &c2b}; - ConstVectorRef vec_ref_a(vec_a); - ConstVectorRef vec_ref_b(vec_ref_a); // Up-cast - Vector 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 vec_a{&c2a, &c2b}; - ConstVectorRef vec_ref_a(vec_a); - ConstVectorRef vec_ref_b(vec_ref_a); // Up-cast - Vector 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 vec_a{"one", "two"}; - ConstVectorRef vec_ref(vec_a); - Vector 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 vec_a{&c2a, &c2b}; - ConstVectorRef vec_ref(vec_a); - EXPECT_EQ(vec_ref[0], &c2a); - EXPECT_EQ(vec_ref[1], &c2b); - Vector 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 vec_a{&c2a, &c2b}; - ConstVectorRef vec_ref(vec_a); - EXPECT_EQ(vec_ref[0], &c2a); - EXPECT_EQ(vec_ref[1], &c2b); - Vector 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 vec_a{&c2a, &c2b}; - VectorRef vec_ref_a(vec_a); - ConstVectorRef vec_ref_b(vec_ref_a); - EXPECT_EQ(vec_ref_b[0], &c2a); - EXPECT_EQ(vec_ref_b[1], &c2b); - Vector 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 vec_a{&c2a, &c2b}; - VectorRef vec_ref_a(vec_a); - ConstVectorRef vec_ref_b(vec_ref_a); - EXPECT_EQ(vec_ref_b[0], &c2a); - EXPECT_EQ(vec_ref_b[1], &c2b); - Vector 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 vec_a{&c2a, &c2b}; - VectorRef vec_ref_a(vec_a); - ConstVectorRef vec_ref_b(vec_ref_a); - EXPECT_EQ(vec_ref_b[0], &c2a); - EXPECT_EQ(vec_ref_b[1], &c2b); - Vector 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 vec{"one", "two"}; - ConstVectorRef vec_ref(vec); - static_assert(std::is_const_v>); - EXPECT_EQ(vec_ref[0], "one"); - EXPECT_EQ(vec_ref[1], "two"); -} - -TEST(TintVectorConstRefTest, ConstIndex) { - Vector vec{"one", "two"}; - const ConstVectorRef vec_ref(vec); - static_assert(std::is_const_v>); - EXPECT_EQ(vec_ref[0], "one"); - EXPECT_EQ(vec_ref[1], "two"); -} - -TEST(TintVectorConstRefTest, Length) { - Vector vec{"one", "two", "three"}; - ConstVectorRef vec_ref(vec); - EXPECT_EQ(vec_ref.Length(), 3u); -} - -TEST(TintVectorConstRefTest, Capacity) { - Vector vec{"one", "two", "three"}; - ConstVectorRef vec_ref(vec); - EXPECT_EQ(vec_ref.Capacity(), 5u); -} - -TEST(TintVectorConstRefTest, IsEmpty) { - Vector vec; - ConstVectorRef 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 vec{"front", "mid", "back"}; - ConstVectorRef vec_ref(vec); - static_assert(std::is_const_v>); - static_assert(std::is_const_v>); - EXPECT_EQ(vec_ref.Front(), "front"); - EXPECT_EQ(vec_ref.Back(), "back"); -} - -TEST(TintVectorConstRefTest, ConstFrontBack) { - Vector vec{"front", "mid", "back"}; - const ConstVectorRef vec_ref(vec); - static_assert(std::is_const_v>); - static_assert(std::is_const_v>); - EXPECT_EQ(vec_ref.Front(), "front"); - EXPECT_EQ(vec_ref.Back(), "back"); -} - -TEST(TintVectorConstRefTest, BeginEnd) { - Vector vec{"front", "mid", "back"}; - ConstVectorRef vec_ref(vec); - static_assert(std::is_const_v>); - static_assert(std::is_const_v>); - EXPECT_EQ(vec_ref.begin(), &vec[0]); - EXPECT_EQ(vec_ref.end(), &vec[0] + 3); -} - -TEST(TintVectorConstRefTest, ConstBeginEnd) { - Vector vec{"front", "mid", "back"}; - const ConstVectorRef vec_ref(vec); - static_assert(std::is_const_v>); - static_assert(std::is_const_v>); - EXPECT_EQ(vec_ref.begin(), &vec[0]); - EXPECT_EQ(vec_ref.end(), &vec[0] + 3); -} - } // namespace } // namespace tint::utils