diff --git a/src/tint/utils/hash_test.cc b/src/tint/utils/hash_test.cc index 9e60a6627d..6ce6820630 100644 --- a/src/tint/utils/hash_test.cc +++ b/src/tint/utils/hash_test.cc @@ -44,10 +44,10 @@ TEST(HashTests, StdVector) { } TEST(HashTests, TintVector) { - EXPECT_EQ(Hash(Vector({})), Hash(Vector({}))); - EXPECT_EQ(Hash(Vector({1, 2, 3})), Hash(Vector({1, 2, 3}))); - EXPECT_NE(Hash(Vector({1, 2, 3})), Hash(Vector({1, 2, 4}))); - EXPECT_NE(Hash(Vector({1, 2, 3})), Hash(Vector({1, 2, 3, 4}))); + EXPECT_EQ(Hash(Vector({})), Hash(Vector({}))); + EXPECT_EQ(Hash(Vector({1, 2, 3})), Hash(Vector({1, 2, 3}))); + EXPECT_NE(Hash(Vector({1, 2, 3})), Hash(Vector({1, 2, 4}))); + EXPECT_NE(Hash(Vector({1, 2, 3})), Hash(Vector({1, 2, 3, 4}))); EXPECT_EQ(Hash(Vector({1, 2, 3})), Hash(Vector({1, 2, 3}))); EXPECT_EQ(Hash(Vector({1, 2, 3})), Hash(Vector({1, 2, 3}))); } diff --git a/src/tint/utils/transform.h b/src/tint/utils/transform.h index 0c912635f7..412dbed3cb 100644 --- a/src/tint/utils/transform.h +++ b/src/tint/utils/transform.h @@ -59,10 +59,12 @@ auto Transform(const std::vector& in, TRANSFORMER&& transform) /// @returns a new vector with each element of the source vector transformed by `transform`. template auto Transform(const Vector& in, TRANSFORMER&& transform) - -> Vector { - Vector result(in.Length()); - for (size_t i = 0; i < result.Length(); ++i) { - result[i] = transform(in[i]); + -> 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; } @@ -74,9 +76,11 @@ auto Transform(const Vector& in, TRANSFORMER&& transform) template auto Transform(const Vector& in, TRANSFORMER&& transform) -> Vector { - Vector result(in.Length()); - for (size_t i = 0; i < result.Length(); ++i) { - result[i] = transform(in[i], i); + 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; } @@ -89,9 +93,11 @@ auto Transform(const Vector& in, TRANSFORMER&& transform) template auto Transform(const VectorRef& in, TRANSFORMER&& transform) -> Vector { - Vector result(in.Length()); - for (size_t i = 0; i < result.Length(); ++i) { - result[i] = transform(in[i]); + 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; } @@ -104,9 +110,11 @@ auto Transform(const VectorRef& in, TRANSFORMER&& transform) template auto Transform(const VectorRef& in, TRANSFORMER&& transform) -> Vector { - Vector result(in.Length()); - for (size_t i = 0; i < result.Length(); ++i) { - result[i] = transform(in[i], i); + 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; } @@ -119,9 +127,11 @@ auto Transform(const VectorRef& in, TRANSFORMER&& transform) template auto Transform(ConstVectorRef in, TRANSFORMER&& transform) -> Vector { - Vector result(in.Length()); - for (size_t i = 0; i < result.Length(); ++i) { - result[i] = transform(in[i]); + 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; } @@ -134,9 +144,11 @@ auto Transform(ConstVectorRef in, TRANSFORMER&& transform) template auto Transform(ConstVectorRef in, TRANSFORMER&& transform) -> Vector { - Vector result(in.Length()); - for (size_t i = 0; i < result.Length(); ++i) { - result[i] = transform(in[i], i); + 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; } diff --git a/src/tint/utils/vector.h b/src/tint/utils/vector.h index daac42cff2..d339a49714 100644 --- a/src/tint/utils/vector.h +++ b/src/tint/utils/vector.h @@ -22,6 +22,8 @@ #include #include +#include "src/tint/castable.h" +#include "src/tint/traits.h" #include "src/tint/utils/bitcast.h" namespace tint::utils { @@ -36,8 +38,6 @@ class ConstVectorRef; namespace tint::utils { -namespace detail { - /// A slice represents a contigious array of elements of type T. template struct Slice { @@ -97,7 +97,42 @@ struct Slice { auto rend() const { return std::reverse_iterator(begin()); } }; -} // namespace detail +/// Evaluates whether a `vector` and be reinterpreted as a `vector`. +/// Vectors can be reinterpreted if both `FROM` and `TO` are pointers to a type that derives from +/// CastableBase, and the pointee type of `TO` is of the same type as, or is an ancestor of the +/// pointee type of `FROM`. Vectors of non-`const` Castable pointers can be converted to a vector of +/// `const` Castable pointers. +template +static constexpr bool CanReinterpretSlice = + // TO and FROM are both pointer types + std::is_pointer_v && std::is_pointer_v && // + // const can only be applied, not removed + (std::is_const_v> || + !std::is_const_v>)&& // + // TO and FROM are both Castable + IsCastable, std::remove_pointer_t> && + // FROM is of, or derives from TO + traits::IsTypeOrDerived, std::remove_pointer_t>; + +/// Reinterprets `const Slice*` as `const Slice*` +/// @param slice a pointer to the slice to reinterpret +/// @returns the reinterpreted slice +/// @see CanReinterpretSlice +template +const Slice* ReinterpretSlice(const Slice* slice) { + static_assert(CanReinterpretSlice); + return Bitcast*>(slice); +} + +/// Reinterprets `Slice*` as `Slice*` +/// @param slice a pointer to the slice to reinterpret +/// @returns the reinterpreted slice +/// @see CanReinterpretSlice +template +Slice* ReinterpretSlice(Slice* slice) { + static_assert(CanReinterpretSlice); + return Bitcast*>(slice); +} /// Vector is a small-object-optimized, dynamically-sized vector of contigious elements of type T. /// @@ -118,39 +153,20 @@ struct Slice { /// array'. This reduces memory copying, but may incur additional memory usage. /// * Resizing, or popping elements from a vector that has spilled to a heap allocation does not /// revert back to using the 'small array'. Again, this is to reduce memory copying. -template +template class Vector { public: /// Type of `T`. using value_type = T; + /// Value of `N` + static constexpr size_t static_length = N; /// Constructor Vector() = default; - /// Constructor - /// @param length the initial length of the vector. Elements will be zero-initialized. - explicit Vector(size_t length) { - Reserve(length); - for (size_t i = 0; i < length; i++) { - new (&impl_.slice.data[i]) T{}; - } - impl_.slice.len = length; - } - - /// Constructor - /// @param length the initial length of the vector - /// @param value the value to copy into each element of the vector - Vector(size_t length, const T& value) { - Reserve(length); - for (size_t i = 0; i < length; i++) { - new (&impl_.slice.data[i]) T{value}; - } - impl_.slice.len = length; - } - /// Constructor /// @param elements the elements to place into the vector - explicit Vector(std::initializer_list elements) { + Vector(std::initializer_list elements) { Reserve(elements.size()); for (auto& el : elements) { new (&impl_.slice.data[impl_.slice.len++]) T{el}; @@ -179,17 +195,32 @@ class Vector { MoveOrCopy(VectorRef(std::move(other))); } + /// Copy constructor with covariance / const conversion + /// @param other the vector to copy + /// @see CanReinterpretSlice for rules about conversion + template >> + Vector(const Vector& other) { // NOLINT(runtime/explicit) + Copy(*ReinterpretSlice(&other.impl_.slice)); + } + + /// Move constructor with covariance / const conversion + /// @param other the vector to move + /// @see CanReinterpretSlice for rules about conversion + template >> + Vector(Vector&& other) { // NOLINT(runtime/explicit) + MoveOrCopy(VectorRef(std::move(other))); + } + /// Move constructor from a mutable vector reference /// @param other the vector reference to move - Vector(VectorRef&& other) { // NOLINT(runtime/explicit) - MoveOrCopy(std::move(other)); - } + explicit Vector(VectorRef&& other) { MoveOrCopy(std::move(other)); } /// Copy constructor from an immutable vector reference /// @param other the vector reference to copy - Vector(const ConstVectorRef& other) { // NOLINT(runtime/explicit) - Copy(other.slice_); - } + explicit Vector(const ConstVectorRef& other) { Copy(other.slice_); } + + /// Move constructor from an immutable vector reference (invalid) + Vector(ConstVectorRef&&) = delete; // NOLINT(runtime/explicit) /// Destructor ~Vector() { ClearAndFree(); } @@ -277,6 +308,20 @@ class Vector { impl_.slice.len = new_len; } + /// Resizes the vector to the given length, expanding capacity if necessary. + /// @param new_len the new vector length + /// @param value the value to copy into the new elements + void Resize(size_t new_len, const T& value) { + Reserve(new_len); + for (size_t i = impl_.slice.len; i > new_len; i--) { // Shrink + impl_.slice.data[i - 1].~T(); + } + for (size_t i = impl_.slice.len; i < new_len; i++) { // Grow + new (&impl_.slice.data[i]) T{value}; + } + impl_.slice.len = new_len; + } + /// Copies all the elements from `other` to this vector, replacing the content of this vector. /// @param other the template @@ -317,7 +362,7 @@ class Vector { if (impl_.slice.len >= impl_.slice.cap) { Grow(); } - new (&impl_.slice.data[impl_.slice.len++]) T(std::forward(args)...); + new (&impl_.slice.data[impl_.slice.len++]) T{std::forward(args)...}; } /// Removes and returns the last element from the vector. @@ -377,7 +422,12 @@ class Vector { friend class ConstVectorRef; /// The slice type used by this vector - using Slice = detail::Slice; + using Slice = utils::Slice; + + template + void AppendVariadic(Ts&&... args) { + ((new (&impl_.slice.data[impl_.slice.len++]) T(std::forward(args))), ...); + } /// Expands the capacity of the vector void Grow() { Reserve(impl_.slice.cap * 2); } @@ -484,6 +534,43 @@ class Vector { std::conditional_t impl_; }; +namespace detail { + +/// Helper for determining the Vector element type (`T`) from the vector's constuctor arguments +/// @tparam IS_CASTABLE true if the types of `Ts` derive from CastableBase +/// @tparam Ts the vector constructor argument types to infer the vector element type from. +template +struct VectorCommonType; + +/// VectorCommonType specialization for non-castable types. +template +struct VectorCommonType { + /// The common T type to use for the vector + using type = std::common_type_t; +}; + +/// VectorCommonType specialization for castable types. +template +struct VectorCommonType { + /// The common Castable type (excluding pointer) + using common_ty = CastableCommonBase...>; + /// The common T type to use for the vector + using type = std::conditional_t<(std::is_const_v> || ...), + const common_ty*, + common_ty*>; +}; + +} // namespace detail + +/// Helper for determining the Vector element type (`T`) from the vector's constuctor arguments +template +using VectorCommonType = + typename detail::VectorCommonType...>, Ts...>::type; + +/// Deduction guide for Vector +template +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. @@ -507,16 +594,16 @@ class Vector { template class VectorRef { /// The slice type used by this vector reference - using Slice = detail::Slice; + using Slice = utils::Slice; public: - /// Constructor from a Vector. - /// @param vector the vector reference + /// 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) {} - /// Constructor from a std::move()'d Vector + /// Constructor from a moved Vector /// @param vector the vector being moved template VectorRef(Vector&& vector) // NOLINT(runtime/explicit) @@ -530,6 +617,32 @@ class VectorRef { /// @param other the vector reference VectorRef(VectorRef&& other) = default; + /// Copy constructor with covariance / const conversion + /// @param other the other vector reference + template >> + VectorRef(const VectorRef& other) // NOLINT(runtime/explicit) + : slice_(*ReinterpretSlice(&other.slice_)), can_move_(false) {} + + /// Move constructor with covariance / const conversion + /// @param other the vector reference + template >> + VectorRef(VectorRef&& other) // NOLINT(runtime/explicit) + : slice_(*ReinterpretSlice(&other.slice_)), can_move_(other.can_move_) {} + + /// Constructor from a Vector with covariance / const conversion + /// @param vector the vector to create a reference of + /// @see CanReinterpretSlice for rules about conversion + template >> + VectorRef(Vector& vector) // NOLINT(runtime/explicit) + : slice_(*ReinterpretSlice(&vector.impl_.slice)), can_move_(false) {} + + /// Constructor from a moved Vector with covariance / const conversion + /// @param vector the vector to create a reference of + /// @see CanReinterpretSlice for rules about conversion + template >> + 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. @@ -587,10 +700,18 @@ class VectorRef { auto rend() const { return slice_.rend(); } private: - /// Friend classes + /// Friend class template friend class Vector; + /// Friend class + template + friend class VectorRef; + + /// Friend class + template + friend class ConstVectorRef; + /// The slice of the vector being referenced. Slice& slice_; /// Whether the slice data is passed by r-value reference, and can be moved. @@ -603,7 +724,7 @@ class VectorRef { template class ConstVectorRef { /// The slice type used by this vector reference - using Slice = detail::Slice; + using Slice = utils::Slice; public: /// Constructor from a Vector. @@ -616,6 +737,34 @@ class ConstVectorRef { /// @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. @@ -650,10 +799,14 @@ class ConstVectorRef { auto rend() const { return slice_.rend(); } private: - /// Friend classes + /// Friend class template friend class Vector; + /// Friend class + template + friend class ConstVectorRef; + /// The slice of the vector being referenced. const Slice& slice_; }; @@ -682,14 +835,6 @@ Vector ToVector(const std::vector& vector) { return out; } -/// Helper for constructing a Vector from a set of elements. -/// The returned Vector's small-array size (`N`) is equal to the number of provided elements. -/// @param elements the elements used to construct the vector. -template -auto MakeVector(Ts&&... elements) { - return Vector({std::forward(elements)...}); -} - } // namespace tint::utils #endif // SRC_TINT_UTILS_VECTOR_H_ diff --git a/src/tint/utils/vector_test.cc b/src/tint/utils/vector_test.cc index 8c2c0cf2f1..6e529dc697 100644 --- a/src/tint/utils/vector_test.cc +++ b/src/tint/utils/vector_test.cc @@ -24,6 +24,11 @@ namespace tint::utils { namespace { +class C0 : public Castable {}; +class C1 : public Castable {}; +class C2a : public Castable {}; +class C2b : public Castable {}; + /// @returns true if the address of el is within the memory of the vector vec. template bool IsInternal(Vector& vec, E& el) { @@ -54,6 +59,46 @@ bool AllExternallyHeld(Vector& vec) { return true; } +//////////////////////////////////////////////////////////////////////////////// +// Static asserts +//////////////////////////////////////////////////////////////////////////////// +static_assert(std::is_same_v, int>); +static_assert(std::is_same_v, int>); +static_assert(std::is_same_v, float>); + +static_assert(std::is_same_v, C0*>); +static_assert(std::is_same_v, const C0*>); + +static_assert(std::is_same_v, C0*>); +static_assert(std::is_same_v, const C0*>); +static_assert(std::is_same_v, const C0*>); +static_assert(std::is_same_v, const C0*>); + +static_assert(std::is_same_v, C1*>); +static_assert(std::is_same_v, const C1*>); +static_assert(std::is_same_v, const C1*>); +static_assert(std::is_same_v, const C1*>); + +static_assert(CanReinterpretSlice, "apply const"); +static_assert(!CanReinterpretSlice, "remove const"); +static_assert(CanReinterpretSlice, "up cast"); +static_assert(CanReinterpretSlice, "up cast"); +static_assert(CanReinterpretSlice, "up cast, apply const"); +static_assert(!CanReinterpretSlice, "up cast, remove const"); +static_assert(!CanReinterpretSlice, "down cast"); +static_assert(!CanReinterpretSlice, "down cast"); +static_assert(!CanReinterpretSlice, "down cast, apply const"); +static_assert(!CanReinterpretSlice, "down cast, remove const"); +static_assert(!CanReinterpretSlice, "down cast, apply const"); +static_assert(!CanReinterpretSlice, "down cast, remove const"); +static_assert(!CanReinterpretSlice, "sideways cast"); +static_assert(!CanReinterpretSlice, "sideways cast"); +static_assert(!CanReinterpretSlice, "sideways cast, apply const"); +static_assert(!CanReinterpretSlice, "sideways cast, remove const"); + +//////////////////////////////////////////////////////////////////////////////// +// TintVectorTest +//////////////////////////////////////////////////////////////////////////////// TEST(TintVectorTest, SmallArray_Empty) { Vector vec; EXPECT_EQ(vec.Length(), 0u); @@ -61,59 +106,12 @@ TEST(TintVectorTest, SmallArray_Empty) { } TEST(TintVectorTest, Empty_NoSmallArray) { - Vector vec; + Vector vec; EXPECT_EQ(vec.Length(), 0u); EXPECT_EQ(vec.Capacity(), 0u); } -TEST(TintVectorTest, SmallArray_ConstructLength_NoSpill) { - Vector vec(2); - EXPECT_EQ(vec.Length(), 2u); - EXPECT_EQ(vec.Capacity(), 2u); - EXPECT_EQ(vec[0], 0); - EXPECT_EQ(vec[1], 0); - EXPECT_TRUE(AllInternallyHeld(vec)); -} - -TEST(TintVectorTest, SmallArray_ConstructLength_WithSpill) { - Vector vec(3); - EXPECT_EQ(vec.Length(), 3u); - EXPECT_EQ(vec.Capacity(), 3u); - EXPECT_EQ(vec[0], 0); - EXPECT_EQ(vec[1], 0); - EXPECT_EQ(vec[2], 0); - EXPECT_TRUE(AllExternallyHeld(vec)); -} - -TEST(TintVectorTest, SmallArray_ConstructLengthValue_NoSpill) { - Vector vec(2, "abc"); - EXPECT_EQ(vec.Length(), 2u); - EXPECT_EQ(vec.Capacity(), 2u); - EXPECT_EQ(vec[0], "abc"); - EXPECT_EQ(vec[1], "abc"); - EXPECT_TRUE(AllInternallyHeld(vec)); -} - -TEST(TintVectorTest, SmallArray_ConstructLengthValue_WithSpill) { - Vector vec(3, "abc"); - EXPECT_EQ(vec.Length(), 3u); - EXPECT_EQ(vec.Capacity(), 3u); - EXPECT_EQ(vec[0], "abc"); - EXPECT_EQ(vec[1], "abc"); - EXPECT_EQ(vec[2], "abc"); - EXPECT_TRUE(AllExternallyHeld(vec)); -} - -TEST(TintVectorTest, ConstructLength_NoSmallArray) { - Vector vec(2); - EXPECT_EQ(vec.Length(), 2u); - EXPECT_EQ(vec.Capacity(), 2u); - EXPECT_EQ(vec[0], 0); - EXPECT_EQ(vec[1], 0); - EXPECT_TRUE(AllExternallyHeld(vec)); -} - -TEST(TintVectorTest, ConstructInitializerList_NoSpill) { +TEST(TintVectorTest, InitializerList_NoSpill) { Vector vec{"one", "two"}; EXPECT_EQ(vec.Length(), 2u); EXPECT_EQ(vec.Capacity(), 2u); @@ -122,7 +120,7 @@ TEST(TintVectorTest, ConstructInitializerList_NoSpill) { EXPECT_TRUE(AllInternallyHeld(vec)); } -TEST(TintVectorTest, ConstructInitializerList_WithSpill) { +TEST(TintVectorTest, InitializerList_WithSpill) { Vector vec{"one", "two", "three"}; EXPECT_EQ(vec.Length(), 3u); EXPECT_EQ(vec.Capacity(), 3u); @@ -132,8 +130,8 @@ TEST(TintVectorTest, ConstructInitializerList_WithSpill) { EXPECT_TRUE(AllExternallyHeld(vec)); } -TEST(TintVectorTest, ConstructInitializerList_NoSmallArray) { - Vector vec{"one", "two"}; +TEST(TintVectorTest, InitializerList_NoSmallArray) { + Vector vec{"one", "two"}; EXPECT_EQ(vec.Length(), 2u); EXPECT_EQ(vec.Capacity(), 2u); EXPECT_EQ(vec[0], "one"); @@ -141,9 +139,180 @@ TEST(TintVectorTest, ConstructInitializerList_NoSmallArray) { EXPECT_TRUE(AllExternallyHeld(vec)); } -TEST(TintVectorTest, CopyCtor_NoSpill_N2_to_N2) { +TEST(TintVectorTest, InferTN_1CString) { + auto vec = Vector{"one"}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 1u); + EXPECT_EQ(vec.Length(), 1u); + EXPECT_EQ(vec.Capacity(), 1u); + EXPECT_STREQ(vec[0], "one"); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_2CStrings) { + auto vec = Vector{"one", "two"}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 2u); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_STREQ(vec[0], "one"); + EXPECT_STREQ(vec[1], "two"); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_IntFloat) { + auto vec = Vector{1, 2.0f}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 2u); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], 1.0f); + EXPECT_EQ(vec[1], 2.0f); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_IntDoubleIntDouble) { + auto vec = Vector{1, 2.0, 3, 4.0}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 4u); + EXPECT_EQ(vec.Length(), 4u); + EXPECT_EQ(vec.Capacity(), 4u); + EXPECT_EQ(vec[0], 1.0); + EXPECT_EQ(vec[1], 2.0); + EXPECT_EQ(vec[2], 3.0); + EXPECT_EQ(vec[3], 4.0); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_C0) { + C0 c0; + auto vec = Vector{&c0}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 1u); + EXPECT_EQ(vec.Length(), 1u); + EXPECT_EQ(vec.Capacity(), 1u); + EXPECT_EQ(vec[0], &c0); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_ConstC0) { + const C0 c0; + auto vec = Vector{&c0}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 1u); + EXPECT_EQ(vec.Length(), 1u); + EXPECT_EQ(vec.Capacity(), 1u); + EXPECT_EQ(vec[0], &c0); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_C0C1) { + C0 c0; + C1 c1; + auto vec = Vector{&c0, &c1}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 2u); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], &c0); + EXPECT_EQ(vec[1], &c1); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_ConstC0C1) { + const C0 c0; + C1 c1; + auto vec = Vector{&c0, &c1}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 2u); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], &c0); + EXPECT_EQ(vec[1], &c1); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_C0ConstC1) { + C0 c0; + const C1 c1; + auto vec = Vector{&c0, &c1}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 2u); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], &c0); + EXPECT_EQ(vec[1], &c1); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_ConstC0ConstC1) { + const C0 c0; + const C1 c1; + auto vec = Vector{&c0, &c1}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 2u); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], &c0); + EXPECT_EQ(vec[1], &c1); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_C2aC2b) { + C2a c2a; + C2b c2b; + auto vec = Vector{&c2a, &c2b}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 2u); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], &c2a); + EXPECT_EQ(vec[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_ConstC2aC2b) { + const C2a c2a; + C2b c2b; + auto vec = Vector{&c2a, &c2b}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 2u); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], &c2a); + EXPECT_EQ(vec[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_C2aConstC2b) { + C2a c2a; + const C2b c2b; + auto vec = Vector{&c2a, &c2b}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 2u); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], &c2a); + EXPECT_EQ(vec[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, InferTN_ConstC2aConstC2b) { + const C2a c2a; + const C2b c2b; + auto vec = Vector{&c2a, &c2b}; + static_assert(std::is_same_v); + static_assert(decltype(vec)::static_length == 2u); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], &c2a); + EXPECT_EQ(vec[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, CopyVector_NoSpill_N2_to_N2) { Vector vec_a{"hello", "world"}; - Vector vec_b{vec_a}; + Vector vec_b(vec_a); EXPECT_EQ(vec_b.Length(), 2u); EXPECT_EQ(vec_b.Capacity(), 2u); EXPECT_EQ(vec_b[0], "hello"); @@ -151,9 +320,9 @@ TEST(TintVectorTest, CopyCtor_NoSpill_N2_to_N2) { EXPECT_TRUE(AllInternallyHeld(vec_b)); } -TEST(TintVectorTest, CopyCtor_WithSpill_N2_to_N2) { +TEST(TintVectorTest, CopyVector_WithSpill_N2_to_N2) { Vector vec_a{"hello", "world", "spill"}; - Vector vec_b{vec_a}; + Vector vec_b(vec_a); EXPECT_EQ(vec_b.Length(), 3u); EXPECT_EQ(vec_b.Capacity(), 3u); EXPECT_EQ(vec_b[0], "hello"); @@ -162,30 +331,9 @@ TEST(TintVectorTest, CopyCtor_WithSpill_N2_to_N2) { EXPECT_TRUE(AllExternallyHeld(vec_b)); } -TEST(TintVectorTest, MoveCtor_NoSpill_N2_to_N2) { +TEST(TintVectorTest, CopyVector_NoSpill_N2_to_N1) { Vector vec_a{"hello", "world"}; - Vector vec_b{std::move(vec_a)}; - 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, MoveCtor_WithSpill_N2_to_N2) { - Vector vec_a{"hello", "world", "spill"}; - Vector vec_b{std::move(vec_a)}; - 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, CopyCtor_NoSpill_N2_to_N1) { - Vector vec_a{"hello", "world"}; - Vector vec_b{vec_a}; + Vector vec_b(vec_a); EXPECT_EQ(vec_b.Length(), 2u); EXPECT_EQ(vec_b.Capacity(), 2u); EXPECT_EQ(vec_b[0], "hello"); @@ -193,9 +341,9 @@ TEST(TintVectorTest, CopyCtor_NoSpill_N2_to_N1) { EXPECT_TRUE(AllExternallyHeld(vec_b)); } -TEST(TintVectorTest, CopyCtor_WithSpill_N2_to_N1) { +TEST(TintVectorTest, CopyVector_WithSpill_N2_to_N1) { Vector vec_a{"hello", "world", "spill"}; - Vector vec_b{vec_a}; + Vector vec_b(vec_a); EXPECT_EQ(vec_b.Length(), 3u); EXPECT_EQ(vec_b.Capacity(), 3u); EXPECT_EQ(vec_b[0], "hello"); @@ -204,9 +352,111 @@ TEST(TintVectorTest, CopyCtor_WithSpill_N2_to_N1) { EXPECT_TRUE(AllExternallyHeld(vec_b)); } -TEST(TintVectorTest, MoveCtor_NoSpill_N2_to_N1) { +TEST(TintVectorTest, CopyVector_NoSpill_N2_to_N3) { Vector vec_a{"hello", "world"}; - Vector vec_b{std::move(vec_a)}; + Vector vec_b(vec_a); + 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, CopyVector_WithSpill_N2_to_N3) { + Vector vec_a{"hello", "world", "spill"}; + Vector vec_b(vec_a); + 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, CopyVector_NoMoveUpcast_NoSpill) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + Vector vec_b(vec_a); // No move + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorTest, CopyVector_NoMoveUpcast_WithSpill) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + Vector vec_b(vec_a); // No move + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorTest, CopyVector_NoMoveAddConst_NoSpill) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + Vector vec_b(vec_a); // No move + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorTest, CopyVector_NoMoveAddConst_WithSpill) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + Vector vec_b(vec_a); // No move + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorTest, CopyVector_NoMoveUpcastAndAddConst_NoSpill) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + Vector vec_b(vec_a); // No move + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorTest, CopyVector_NoMoveUpcastAndAddConst_WithSpill) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + Vector vec_b(vec_a); // No move + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorTest, MoveVector_NoSpill_N2_to_N2) { + Vector vec_a{"hello", "world"}; + Vector vec_b(std::move(vec_a)); + 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, MoveVector_WithSpill_N2_to_N2) { + Vector vec_a{"hello", "world", "spill"}; + Vector vec_b(std::move(vec_a)); + 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, MoveVector_NoSpill_N2_to_N1) { + Vector vec_a{"hello", "world"}; + Vector vec_b(std::move(vec_a)); EXPECT_EQ(vec_b.Length(), 2u); EXPECT_EQ(vec_b.Capacity(), 2u); EXPECT_EQ(vec_b[0], "hello"); @@ -214,9 +464,9 @@ TEST(TintVectorTest, MoveCtor_NoSpill_N2_to_N1) { EXPECT_TRUE(AllExternallyHeld(vec_b)); } -TEST(TintVectorTest, MoveCtor_WithSpill_N2_to_N1) { +TEST(TintVectorTest, MoveVector_WithSpill_N2_to_N1) { Vector vec_a{"hello", "world", "spill"}; - Vector vec_b{std::move(vec_a)}; + Vector vec_b(std::move(vec_a)); EXPECT_EQ(vec_b.Length(), 3u); EXPECT_EQ(vec_b.Capacity(), 3u); EXPECT_EQ(vec_b[0], "hello"); @@ -225,9 +475,9 @@ TEST(TintVectorTest, MoveCtor_WithSpill_N2_to_N1) { EXPECT_TRUE(AllExternallyHeld(vec_b)); } -TEST(TintVectorTest, CopyCtor_NoSpill_N2_to_N3) { +TEST(TintVectorTest, MoveVector_NoSpill_N2_to_N3) { Vector vec_a{"hello", "world"}; - Vector vec_b{vec_a}; + Vector vec_b(std::move(vec_a)); EXPECT_EQ(vec_b.Length(), 2u); EXPECT_EQ(vec_b.Capacity(), 3u); EXPECT_EQ(vec_b[0], "hello"); @@ -235,30 +485,9 @@ TEST(TintVectorTest, CopyCtor_NoSpill_N2_to_N3) { EXPECT_TRUE(AllInternallyHeld(vec_b)); } -TEST(TintVectorTest, CopyCtor_WithSpill_N2_to_N3) { +TEST(TintVectorTest, MoveVector_WithSpill_N2_to_N3) { Vector vec_a{"hello", "world", "spill"}; - Vector vec_b{vec_a}; - 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, MoveCtor_NoSpill_N2_to_N3) { - Vector vec_a{"hello", "world"}; - Vector vec_b{std::move(vec_a)}; - 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, MoveCtor_WithSpill_N2_to_N3) { - Vector vec_a{"hello", "world", "spill"}; - Vector vec_b{std::move(vec_a)}; + Vector vec_b(std::move(vec_a)); EXPECT_EQ(vec_b.Length(), 3u); EXPECT_EQ(vec_b.Capacity(), 3u); EXPECT_EQ(vec_b[0], "hello"); @@ -267,6 +496,66 @@ TEST(TintVectorTest, MoveCtor_WithSpill_N2_to_N3) { EXPECT_TRUE(AllExternallyHeld(vec_b)); } +TEST(TintVectorTest, MoveVector_Upcast_NoSpill) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + Vector vec_b(std::move(vec_a)); // Move + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorTest, MoveVector_Upcast_WithSpill) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + Vector vec_b(std::move(vec_a)); // Move + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied +} + +TEST(TintVectorTest, MoveVector_AddConst_NoSpill) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + Vector vec_b(std::move(vec_a)); // Move + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorTest, MoveVector_AddConst_WithSpill) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + Vector vec_b(std::move(vec_a)); // Move + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied +} + +TEST(TintVectorTest, MoveVector_UpcastAndAddConst_NoSpill) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + Vector vec_b(std::move(vec_a)); // Move + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorTest, MoveVector_UpcastAndAddConst_WithSpill) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + Vector vec_b(std::move(vec_a)); // Move + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied +} + TEST(TintVectorTest, CopyAssign_NoSpill_N2_to_N2) { Vector vec_a{"hello", "world"}; Vector vec_b; @@ -290,29 +579,6 @@ TEST(TintVectorTest, CopyAssign_WithSpill_N2_to_N2) { EXPECT_TRUE(AllExternallyHeld(vec_b)); } -TEST(TintVectorTest, MoveAssign_NoSpill_N2_to_N2) { - Vector vec_a{"hello", "world"}; - Vector vec_b; - vec_b = std::move(vec_a); - 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, MoveAssign_WithSpill_N2_to_N2) { - Vector vec_a{"hello", "world", "spill"}; - Vector vec_b; - vec_b = std::move(vec_a); - 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, CopyAssign_NoSpill_N2_to_N1) { Vector vec_a{"hello", "world"}; Vector vec_b; @@ -336,29 +602,6 @@ TEST(TintVectorTest, CopyAssign_WithSpill_N2_to_N1) { EXPECT_TRUE(AllExternallyHeld(vec_b)); } -TEST(TintVectorTest, MoveAssign_NoSpill_N2_to_N1) { - Vector vec_a{"hello", "world"}; - Vector vec_b; - vec_b = std::move(vec_a); - 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, MoveAssign_SpillSpill_N2_to_N1) { - Vector vec_a{"hello", "world", "spill"}; - Vector vec_b; - vec_b = std::move(vec_a); - 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, CopyAssign_NoSpill_N2_to_N3) { Vector vec_a{"hello", "world"}; Vector vec_b; @@ -382,32 +625,9 @@ TEST(TintVectorTest, CopyAssign_WithSpill_N2_to_N3) { EXPECT_TRUE(AllInternallyHeld(vec_b)); } -TEST(TintVectorTest, MoveAssign_NoSpill_N2_to_N3) { - Vector vec_a{"hello", "world"}; - Vector vec_b; - vec_b = std::move(vec_a); - 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, MoveAssign_WithSpill_N2_to_N3) { - Vector vec_a{"hello", "world", "spill"}; - Vector vec_b; - vec_b = std::move(vec_a); - 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, CopyAssign_NoSpill_N2_to_N0) { Vector vec_a{"hello", "world"}; - Vector vec_b; + Vector vec_b; vec_b = vec_a; EXPECT_EQ(vec_b.Length(), 2u); EXPECT_EQ(vec_b.Capacity(), 2u); @@ -418,7 +638,7 @@ TEST(TintVectorTest, CopyAssign_NoSpill_N2_to_N0) { TEST(TintVectorTest, CopyAssign_WithSpill_N2_to_N0) { Vector vec_a{"hello", "world", "spill"}; - Vector vec_b; + Vector vec_b; vec_b = vec_a; EXPECT_EQ(vec_b.Length(), 3u); EXPECT_EQ(vec_b.Capacity(), 3u); @@ -428,29 +648,6 @@ TEST(TintVectorTest, CopyAssign_WithSpill_N2_to_N0) { EXPECT_TRUE(AllExternallyHeld(vec_b)); } -TEST(TintVectorTest, MoveAssign_NoSpill_N2_to_N0) { - Vector vec_a{"hello", "world"}; - Vector vec_b; - vec_b = std::move(vec_a); - 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, MoveAssign_WithSpill_N2_to_N0) { - Vector vec_a{"hello", "world", "spill"}; - Vector vec_b; - vec_b = std::move(vec_a); - 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, CopyAssign_Self_NoSpill) { Vector vec{"hello", "world"}; auto* vec_ptr = &vec; // Used to avoid -Wself-assign-overloaded @@ -473,6 +670,98 @@ TEST(TintVectorTest, CopyAssign_Self_WithSpill) { EXPECT_TRUE(AllExternallyHeld(vec)); } +TEST(TintVectorTest, MoveAssign_NoSpill_N2_to_N2) { + Vector vec_a{"hello", "world"}; + Vector vec_b; + vec_b = std::move(vec_a); + 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, MoveAssign_WithSpill_N2_to_N2) { + Vector vec_a{"hello", "world", "spill"}; + Vector vec_b; + vec_b = std::move(vec_a); + 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, MoveAssign_NoSpill_N2_to_N1) { + Vector vec_a{"hello", "world"}; + Vector vec_b; + vec_b = std::move(vec_a); + 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, MoveAssign_SpillSpill_N2_to_N1) { + Vector vec_a{"hello", "world", "spill"}; + Vector vec_b; + vec_b = std::move(vec_a); + 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, MoveAssign_NoSpill_N2_to_N3) { + Vector vec_a{"hello", "world"}; + Vector vec_b; + vec_b = std::move(vec_a); + 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, MoveAssign_WithSpill_N2_to_N3) { + Vector vec_a{"hello", "world", "spill"}; + Vector vec_b; + vec_b = std::move(vec_a); + 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, MoveAssign_NoSpill_N2_to_N0) { + Vector vec_a{"hello", "world"}; + Vector vec_b; + vec_b = std::move(vec_a); + 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, MoveAssign_WithSpill_N2_to_N0) { + Vector vec_a{"hello", "world", "spill"}; + Vector vec_b; + vec_b = std::move(vec_a); + 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, MoveAssign_Self_NoSpill) { Vector vec{"hello", "world"}; auto* vec_ptr = &vec; // Used to avoid -Wself-move @@ -541,7 +830,7 @@ TEST(TintVectorTest, ConstIndex) { EXPECT_EQ(vec[1], "world"); } -TEST(TintVectorTest, SmallArray_Reserve_NoSpill) { +TEST(TintVectorTest, Reserve_NoSpill) { Vector vec; EXPECT_EQ(vec.Length(), 0u); EXPECT_EQ(vec.Capacity(), 2u); @@ -562,7 +851,7 @@ TEST(TintVectorTest, SmallArray_Reserve_NoSpill) { EXPECT_TRUE(AllInternallyHeld(vec)); } -TEST(TintVectorTest, SmallArray_Reserve_WithSpill) { +TEST(TintVectorTest, Reserve_WithSpill) { Vector vec; EXPECT_EQ(vec.Length(), 0u); EXPECT_EQ(vec.Capacity(), 1u); @@ -584,7 +873,7 @@ TEST(TintVectorTest, SmallArray_Reserve_WithSpill) { EXPECT_TRUE(AllExternallyHeld(vec)); } -TEST(TintVectorTest, SmallArray_Resize_NoSpill) { +TEST(TintVectorTest, ResizeZero_NoSpill) { Vector vec; EXPECT_EQ(vec.Length(), 0u); EXPECT_EQ(vec.Capacity(), 2u); @@ -614,7 +903,7 @@ TEST(TintVectorTest, SmallArray_Resize_NoSpill) { EXPECT_TRUE(AllInternallyHeld(vec)); } -TEST(TintVectorTest, SmallArray_Resize_WithSpill) { +TEST(TintVectorTest, ResizeZero_WithSpill) { Vector vec; EXPECT_EQ(vec.Length(), 0u); EXPECT_EQ(vec.Capacity(), 1u); @@ -644,8 +933,68 @@ TEST(TintVectorTest, SmallArray_Resize_WithSpill) { EXPECT_TRUE(AllExternallyHeld(vec)); } +TEST(TintVectorTest, ResizeValue_NoSpill) { + Vector vec; + EXPECT_EQ(vec.Length(), 0u); + EXPECT_EQ(vec.Capacity(), 2u); + vec.Resize(1, "meow"); + EXPECT_EQ(vec.Length(), 1u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], "meow"); + EXPECT_TRUE(AllInternallyHeld(vec)); + vec[0] = "hello"; + vec.Resize(2, "woof"); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], "hello"); + EXPECT_EQ(vec[1], "woof"); + EXPECT_TRUE(AllInternallyHeld(vec)); + vec[1] = "world"; + vec.Resize(1, "quack"); + EXPECT_EQ(vec.Length(), 1u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], "hello"); + EXPECT_TRUE(AllInternallyHeld(vec)); + vec.Resize(2, "hiss"); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], "hello"); + EXPECT_EQ(vec[1], "hiss"); + EXPECT_TRUE(AllInternallyHeld(vec)); +} + +TEST(TintVectorTest, ResizeValue_WithSpill) { + Vector vec; + EXPECT_EQ(vec.Length(), 0u); + EXPECT_EQ(vec.Capacity(), 1u); + vec.Resize(1, "meow"); + EXPECT_EQ(vec.Length(), 1u); + EXPECT_EQ(vec.Capacity(), 1u); + EXPECT_EQ(vec[0], "meow"); + EXPECT_TRUE(AllInternallyHeld(vec)); + vec[0] = "hello"; + vec.Resize(2, "woof"); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], "hello"); + EXPECT_EQ(vec[1], "woof"); + EXPECT_TRUE(AllExternallyHeld(vec)); + vec[1] = "world"; + vec.Resize(1, "quack"); + EXPECT_EQ(vec.Length(), 1u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], "hello"); + EXPECT_TRUE(AllExternallyHeld(vec)); + vec.Resize(2, "hiss"); + EXPECT_EQ(vec.Length(), 2u); + EXPECT_EQ(vec.Capacity(), 2u); + EXPECT_EQ(vec[0], "hello"); + EXPECT_EQ(vec[1], "hiss"); + EXPECT_TRUE(AllExternallyHeld(vec)); +} + TEST(TintVectorTest, Reserve_NoSmallArray) { - Vector vec; + Vector vec; EXPECT_EQ(vec.Length(), 0u); EXPECT_EQ(vec.Capacity(), 0u); vec.Reserve(1); @@ -667,7 +1016,7 @@ TEST(TintVectorTest, Reserve_NoSmallArray) { } TEST(TintVectorTest, Resize_NoSmallArray) { - Vector vec; + Vector vec; EXPECT_EQ(vec.Length(), 0u); EXPECT_EQ(vec.Capacity(), 0u); vec.Resize(1); @@ -925,60 +1274,67 @@ TEST(TintVectorTest, Clear_WithSpill) { } TEST(TintVectorTest, PushPop_StringNoSpill) { + const std::string hello = "hello"; + const std::string world = "world"; + Vector vec; EXPECT_EQ(vec.Length(), 0u); EXPECT_TRUE(AllInternallyHeld(vec)); - vec.Push("hello"); + vec.Push(hello); EXPECT_EQ(vec.Length(), 1u); EXPECT_TRUE(AllInternallyHeld(vec)); - vec.Push("world"); + vec.Push(world); EXPECT_EQ(vec.Length(), 2u); EXPECT_TRUE(AllInternallyHeld(vec)); - EXPECT_EQ(vec.Pop(), "world"); + EXPECT_EQ(vec.Pop(), world); EXPECT_EQ(vec.Length(), 1u); EXPECT_TRUE(AllInternallyHeld(vec)); - EXPECT_EQ(vec.Pop(), "hello"); + EXPECT_EQ(vec.Pop(), hello); EXPECT_EQ(vec.Length(), 0u); EXPECT_TRUE(AllInternallyHeld(vec)); } TEST(TintVectorTest, PushPop_StringWithSpill) { + const std::string hello = "hello"; + const std::string world = "world"; + Vector vec; EXPECT_EQ(vec.Length(), 0u); EXPECT_TRUE(AllInternallyHeld(vec)); - vec.Push("hello"); + vec.Push(hello); EXPECT_EQ(vec.Length(), 1u); EXPECT_TRUE(AllInternallyHeld(vec)); - vec.Push("world"); + vec.Push(world); EXPECT_EQ(vec.Length(), 2u); EXPECT_TRUE(AllExternallyHeld(vec)); - EXPECT_EQ(vec.Pop(), "world"); + EXPECT_EQ(vec.Pop(), world); EXPECT_EQ(vec.Length(), 1u); EXPECT_TRUE(AllExternallyHeld(vec)); - EXPECT_EQ(vec.Pop(), "hello"); + EXPECT_EQ(vec.Pop(), hello); EXPECT_EQ(vec.Length(), 0u); EXPECT_TRUE(AllExternallyHeld(vec)); } TEST(TintVectorTest, PushPop_StringMoveNoSpill) { + std::string hello = "hello"; + std::string world = "world"; + Vector vec; EXPECT_EQ(vec.Length(), 0u); EXPECT_TRUE(AllInternallyHeld(vec)); - std::string hello = "hello"; vec.Push(std::move(hello)); EXPECT_EQ(vec.Length(), 1u); EXPECT_TRUE(AllInternallyHeld(vec)); - std::string world = "world"; vec.Push(std::move(world)); EXPECT_EQ(vec.Length(), 2u); EXPECT_TRUE(AllInternallyHeld(vec)); @@ -993,15 +1349,18 @@ TEST(TintVectorTest, PushPop_StringMoveNoSpill) { } TEST(TintVectorTest, PushPop_StringMoveWithSpill) { + std::string hello = "hello"; + std::string world = "world"; + Vector vec; EXPECT_EQ(vec.Length(), 0u); EXPECT_TRUE(AllInternallyHeld(vec)); - vec.Push("hello"); + vec.Push(std::move(hello)); EXPECT_EQ(vec.Length(), 1u); EXPECT_TRUE(AllInternallyHeld(vec)); - vec.Push("world"); + vec.Push(std::move(world)); EXPECT_EQ(vec.Length(), 2u); EXPECT_TRUE(AllExternallyHeld(vec)); @@ -1131,42 +1490,195 @@ TEST(TintVectorTest, ConstBeginEnd_WithSpill) { EXPECT_EQ(vec.end(), &vec[0] + 3); } -TEST(TintVectorRefTest, CtorVectorNoMove) { - Vector vec_a{"one", "two"}; - VectorRef vec_ref(vec_a); // No move - Vector vec_b(std::move(vec_ref)); - EXPECT_EQ(vec_b[0], "one"); - EXPECT_EQ(vec_b[1], "two"); - EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copy, no move -} - -TEST(TintVectorRefTest, CtorVectorMove) { - Vector vec_a{"one", "two"}; - VectorRef vec_ref(std::move(vec_a)); // Move - Vector vec_b(std::move(vec_ref)); - EXPECT_EQ(vec_b[0], "one"); - EXPECT_EQ(vec_b[1], "two"); - EXPECT_TRUE(AllExternallyHeld(vec_b)); // Move, no copy -} - -TEST(TintVectorRefTest, CopyCtor) { +//////////////////////////////////////////////////////////////////////////////// +// TintVectorRefTest +//////////////////////////////////////////////////////////////////////////////// +TEST(TintVectorRefTest, CopyVectorRef) { Vector vec_a{"one", "two"}; VectorRef vec_ref_a(std::move(vec_a)); VectorRef vec_ref_b(vec_ref_a); // No move Vector vec_b(std::move(vec_ref_b)); EXPECT_EQ(vec_b[0], "one"); EXPECT_EQ(vec_b[1], "two"); - EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copy, no move + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved } -TEST(TintVectorRefTest, MoveCtor) { +TEST(TintVectorRefTest, CopyVectorRef_Upcast) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + VectorRef vec_ref_a(std::move(vec_a)); + VectorRef vec_ref_b(vec_ref_a); // No-move. Up-cast + Vector vec_b(std::move(vec_ref_b)); + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorRefTest, CopyVectorRef_AddConst) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + VectorRef vec_ref_a(std::move(vec_a)); + VectorRef vec_ref_b(vec_ref_a); // No-move. Up-cast + Vector vec_b(std::move(vec_ref_b)); + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorRefTest, CopyVectorRef_UpcastAndAddConst) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + VectorRef vec_ref_a(std::move(vec_a)); + VectorRef vec_ref_b(vec_ref_a); // No-move. Up-cast + Vector vec_b(std::move(vec_ref_b)); + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorRefTest, MoveVectorRef) { Vector vec_a{"one", "two"}; VectorRef vec_ref_a(std::move(vec_a)); // Move VectorRef vec_ref_b(std::move(vec_ref_a)); Vector vec_b(std::move(vec_ref_b)); EXPECT_EQ(vec_b[0], "one"); EXPECT_EQ(vec_b[1], "two"); - EXPECT_TRUE(AllExternallyHeld(vec_b)); // Move, no copy + EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied +} + +TEST(TintVectorRefTest, MoveVectorRef_Upcast) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + VectorRef vec_ref_a(std::move(vec_a)); + VectorRef vec_ref_b(std::move(vec_ref_a)); // Moved. Up-cast + Vector vec_b(std::move(vec_ref_b)); + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied +} + +TEST(TintVectorRefTest, MoveVectorRef_AddConst) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + VectorRef vec_ref_a(std::move(vec_a)); + VectorRef vec_ref_b(std::move(vec_ref_a)); // Moved. Up-cast + Vector vec_b(std::move(vec_ref_b)); + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied +} + +TEST(TintVectorRefTest, MoveVectorRef_UpcastAndAddConst) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + VectorRef vec_ref_a(std::move(vec_a)); + VectorRef vec_ref_b(std::move(vec_ref_a)); // Moved. Up-cast + Vector vec_b(std::move(vec_ref_b)); + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied +} + +TEST(TintVectorRefTest, CopyVector) { + Vector vec_a{"one", "two"}; + VectorRef vec_ref(vec_a); // No move + Vector vec_b(std::move(vec_ref)); + EXPECT_EQ(vec_b[0], "one"); + EXPECT_EQ(vec_b[1], "two"); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorRefTest, CopyVector_Upcast) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + VectorRef vec_ref(vec_a); // No move + EXPECT_EQ(vec_ref[0], &c2a); + EXPECT_EQ(vec_ref[1], &c2b); + Vector vec_b(std::move(vec_ref)); + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorRefTest, CopyVector_AddConst) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + VectorRef vec_ref(vec_a); // No move + EXPECT_EQ(vec_ref[0], &c2a); + EXPECT_EQ(vec_ref[1], &c2b); + Vector vec_b(std::move(vec_ref)); + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorRefTest, CopyVector_UpcastAndAddConst) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + VectorRef vec_ref(vec_a); // No move + EXPECT_EQ(vec_ref[0], &c2a); + EXPECT_EQ(vec_ref[1], &c2b); + Vector vec_b(std::move(vec_ref)); + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved +} + +TEST(TintVectorRefTest, MoveVector) { + Vector vec_a{"one", "two"}; + VectorRef vec_ref(std::move(vec_a)); // Move + Vector vec_b(std::move(vec_ref)); + EXPECT_EQ(vec_b[0], "one"); + EXPECT_EQ(vec_b[1], "two"); + EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied +} + +TEST(TintVectorRefTest, MoveVector_Upcast) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + VectorRef vec_ref(std::move(vec_a)); // Move + EXPECT_EQ(vec_ref[0], &c2a); + EXPECT_EQ(vec_ref[1], &c2b); + Vector vec_b(std::move(vec_ref)); + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied +} + +TEST(TintVectorRefTest, MoveVector_AddConst) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + VectorRef vec_ref(std::move(vec_a)); // Move + EXPECT_EQ(vec_ref[0], &c2a); + EXPECT_EQ(vec_ref[1], &c2b); + Vector vec_b(std::move(vec_ref)); + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied +} + +TEST(TintVectorRefTest, MoveVector_UpcastAndAddConst) { + C2a c2a; + C2b c2b; + Vector vec_a{&c2a, &c2b}; + VectorRef vec_ref(std::move(vec_a)); // Move + EXPECT_EQ(vec_ref[0], &c2a); + EXPECT_EQ(vec_ref[1], &c2b); + Vector vec_b(std::move(vec_ref)); + EXPECT_EQ(vec_b[0], &c2a); + EXPECT_EQ(vec_b[1], &c2b); + EXPECT_TRUE(AllExternallyHeld(vec_b)); // Moved, not copied } TEST(TintVectorRefTest, Index) { @@ -1243,42 +1755,130 @@ TEST(TintVectorRefTest, ConstBeginEnd) { EXPECT_EQ(vec_ref.end(), &vec[0] + 3); } -TEST(TintVectorConstRefTest, CtorVectorNoMove) { +//////////////////////////////////////////////////////////////////////////////// +// TintVectorConstRefTest +//////////////////////////////////////////////////////////////////////////////// +TEST(TintVectorConstRefTest, CopyVectorConstRef) { Vector vec_a{"one", "two"}; - ConstVectorRef vec_ref(vec_a); // No move - Vector vec_b(std::move(vec_ref)); + 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)); // Copy, no move + EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copied, not moved } -TEST(TintVectorConstRefTest, CtorVectorMove) { - Vector vec_a{"one", "two"}; - ConstVectorRef vec_ref(std::move(vec_a)); // Move - Vector vec_b(std::move(vec_ref)); - EXPECT_EQ(vec_b[0], "one"); - EXPECT_EQ(vec_b[1], "two"); - EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copy, no move +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, CopyCtor) { - Vector vec_a{"one", "two"}; - ConstVectorRef vec_ref_a(std::move(vec_a)); - ConstVectorRef vec_ref_b(vec_ref_a); // No move - Vector vec_b(std::move(vec_ref_b)); - EXPECT_EQ(vec_b[0], "one"); - EXPECT_EQ(vec_b[1], "two"); - EXPECT_TRUE(AllInternallyHeld(vec_b)); // Copy, no move +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, MoveCtor) { +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_a(std::move(vec_a)); // Move - ConstVectorRef vec_ref_b(std::move(vec_ref_a)); - Vector vec_b(std::move(vec_ref_b)); + 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)); // Copy, no move + 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) { @@ -1357,3 +1957,8 @@ TEST(TintVectorConstRefTest, ConstBeginEnd) { } // namespace } // namespace tint::utils + +TINT_INSTANTIATE_TYPEINFO(tint::utils::C0); +TINT_INSTANTIATE_TYPEINFO(tint::utils::C1); +TINT_INSTANTIATE_TYPEINFO(tint::utils::C2a); +TINT_INSTANTIATE_TYPEINFO(tint::utils::C2b);