// Copyright 2021 The libgav1 Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "src/utils/vector.h" #include #include #include #include "gtest/gtest.h" #include "src/utils/compiler_attributes.h" #if LIBGAV1_MSAN #include #endif namespace libgav1 { namespace { class Foo { public: Foo() = default; int x() const { return x_; } private: int x_ = 38; }; class Point { public: Point(int x, int y) : x_(x), y_(y) {} int x() const { return x_; } int y() const { return y_; } private: int x_; int y_; }; TEST(VectorTest, NoCtor) { VectorNoCtor v; EXPECT_TRUE(v.resize(100)); Vector w; EXPECT_TRUE(w.resize(100)); #if LIBGAV1_MSAN // Use MemorySanitizer to check VectorNoCtor::resize() does not initialize // the memory while Vector::resize() does. // // __msan_test_shadow(const void *x, uptr size) returns the offset of the // first (at least partially) poisoned byte in the range, or -1 if the whole // range is good. for (size_t i = 0; i < 100; ++i) { EXPECT_EQ(__msan_test_shadow(&v[i], sizeof(int)), 0); EXPECT_EQ(__msan_test_shadow(&w[i], sizeof(int)), -1); } #endif } TEST(VectorTest, Constructor) { Vector v; EXPECT_TRUE(v.resize(100)); for (const Foo& foo : v) { EXPECT_EQ(foo.x(), 38); } } TEST(VectorTest, PushBack) { // Create a vector containing integers Vector v; EXPECT_TRUE(v.reserve(8)); EXPECT_EQ(v.size(), 0); EXPECT_TRUE(v.push_back(25)); EXPECT_EQ(v.size(), 1); EXPECT_EQ(v[0], 25); EXPECT_TRUE(v.push_back(13)); EXPECT_EQ(v.size(), 2); EXPECT_EQ(v[0], 25); EXPECT_EQ(v[1], 13); } TEST(VectorTest, PushBackUnchecked) { Vector> v; EXPECT_TRUE(v.reserve(2)); EXPECT_EQ(v.size(), 0); std::unique_ptr point(new (std::nothrow) Point(1, 2)); EXPECT_NE(point, nullptr); v.push_back_unchecked(std::move(point)); EXPECT_EQ(v.size(), 1); EXPECT_EQ(v[0]->x(), 1); EXPECT_EQ(v[0]->y(), 2); point.reset(new (std::nothrow) Point(3, 4)); EXPECT_NE(point, nullptr); v.push_back_unchecked(std::move(point)); EXPECT_EQ(v.size(), 2); EXPECT_EQ(v[0]->x(), 1); EXPECT_EQ(v[0]->y(), 2); EXPECT_EQ(v[1]->x(), 3); EXPECT_EQ(v[1]->y(), 4); } TEST(VectorTest, EmplaceBack) { Vector v; EXPECT_EQ(v.size(), 0); EXPECT_TRUE(v.emplace_back(1, 2)); EXPECT_EQ(v.size(), 1); EXPECT_EQ(v[0].x(), 1); EXPECT_EQ(v[0].y(), 2); EXPECT_TRUE(v.emplace_back(3, 4)); EXPECT_EQ(v.size(), 2); EXPECT_EQ(v[0].x(), 1); EXPECT_EQ(v[0].y(), 2); EXPECT_EQ(v[1].x(), 3); EXPECT_EQ(v[1].y(), 4); } // Copy constructor and assignment are deleted, but move constructor and // assignment are OK. TEST(VectorTest, Move) { Vector ints1; EXPECT_TRUE(ints1.reserve(4)); EXPECT_TRUE(ints1.push_back(2)); EXPECT_TRUE(ints1.push_back(3)); EXPECT_TRUE(ints1.push_back(5)); EXPECT_TRUE(ints1.push_back(7)); // Move constructor. Vector ints2(std::move(ints1)); EXPECT_EQ(ints2.size(), 4); EXPECT_EQ(ints2[0], 2); EXPECT_EQ(ints2[1], 3); EXPECT_EQ(ints2[2], 5); EXPECT_EQ(ints2[3], 7); // Move assignment. Vector ints3; EXPECT_TRUE(ints3.reserve(1)); EXPECT_TRUE(ints3.push_back(11)); ints3 = std::move(ints2); EXPECT_EQ(ints3.size(), 4); EXPECT_EQ(ints3[0], 2); EXPECT_EQ(ints3[1], 3); EXPECT_EQ(ints3[2], 5); EXPECT_EQ(ints3[3], 7); } TEST(VectorTest, Erase) { Vector ints; EXPECT_TRUE(ints.reserve(4)); EXPECT_TRUE(ints.push_back(2)); EXPECT_TRUE(ints.push_back(3)); EXPECT_TRUE(ints.push_back(5)); EXPECT_TRUE(ints.push_back(7)); EXPECT_EQ(ints.size(), 4); EXPECT_EQ(ints[0], 2); EXPECT_EQ(ints[1], 3); EXPECT_EQ(ints[2], 5); EXPECT_EQ(ints[3], 7); ints.erase(ints.begin()); EXPECT_EQ(ints.size(), 3); EXPECT_EQ(ints[0], 3); EXPECT_EQ(ints[1], 5); EXPECT_EQ(ints[2], 7); } TEST(VectorTest, EraseNonTrivial) { // A simple class that sets an int value to 0 in the destructor. class Cleaner { public: explicit Cleaner(int* value) : value_(value) {} ~Cleaner() { *value_ = 0; } int value() const { return *value_; } private: int* value_; }; int value1 = 100; int value2 = 200; Vector> v; EXPECT_TRUE(v.reserve(2)); EXPECT_EQ(v.capacity(), 2); std::unique_ptr c(new (std::nothrow) Cleaner(&value1)); EXPECT_NE(c, nullptr); EXPECT_TRUE(v.push_back(std::move(c))); c.reset(new (std::nothrow) Cleaner(&value2)); EXPECT_NE(c, nullptr); EXPECT_TRUE(v.push_back(std::move(c))); EXPECT_EQ(v.size(), 2); EXPECT_EQ(value1, 100); EXPECT_EQ(value2, 200); v.erase(v.begin()); EXPECT_EQ(v.size(), 1); EXPECT_EQ(v.capacity(), 2); EXPECT_EQ(value1, 0); EXPECT_EQ(value2, 200); EXPECT_EQ(v[0].get()->value(), value2); EXPECT_TRUE(v.shrink_to_fit()); EXPECT_EQ(v.size(), 1); EXPECT_EQ(v.capacity(), 1); EXPECT_EQ(value2, 200); EXPECT_EQ(v[0].get()->value(), value2); v.clear(); EXPECT_TRUE(v.empty()); EXPECT_EQ(value2, 0); } } // namespace } // namespace libgav1