| // 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 <memory> |
| #include <new> |
| #include <utility> |
| |
| #include "gtest/gtest.h" |
| #include "src/utils/compiler_attributes.h" |
| |
| #if LIBGAV1_MSAN |
| #include <sanitizer/msan_interface.h> |
| #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<int> v; |
| EXPECT_TRUE(v.resize(100)); |
| Vector<int> 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<Foo> 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<int> 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<std::unique_ptr<Point>> v; |
| EXPECT_TRUE(v.reserve(2)); |
| EXPECT_EQ(v.size(), 0); |
| |
| std::unique_ptr<Point> 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<Point> 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<int> 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<int> 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<int> 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<int> 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<std::unique_ptr<Cleaner>> v; |
| EXPECT_TRUE(v.reserve(2)); |
| EXPECT_EQ(v.capacity(), 2); |
| |
| std::unique_ptr<Cleaner> 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 |