| //===- llvm/unittest/ADT/SmallVectorTest.cpp ------------------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // SmallVector unit tests. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "gtest/gtest.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/Support/Compiler.h" |
| #include <stdarg.h> |
| #include <list> |
| |
| using namespace llvm; |
| |
| namespace { |
| |
| /// A helper class that counts the total number of constructor and |
| /// destructor calls. |
| class Constructable { |
| private: |
| static int numConstructorCalls; |
| static int numDestructorCalls; |
| static int numAssignmentCalls; |
| |
| int value; |
| |
| public: |
| Constructable() : value(0) { |
| ++numConstructorCalls; |
| } |
| |
| Constructable(int val) : value(val) { |
| ++numConstructorCalls; |
| } |
| |
| Constructable(const Constructable & src) { |
| value = src.value; |
| ++numConstructorCalls; |
| } |
| |
| ~Constructable() { |
| ++numDestructorCalls; |
| } |
| |
| Constructable & operator=(const Constructable & src) { |
| value = src.value; |
| ++numAssignmentCalls; |
| return *this; |
| } |
| |
| int getValue() const { |
| return abs(value); |
| } |
| |
| static void reset() { |
| numConstructorCalls = 0; |
| numDestructorCalls = 0; |
| numAssignmentCalls = 0; |
| } |
| |
| static int getNumConstructorCalls() { |
| return numConstructorCalls; |
| } |
| |
| static int getNumDestructorCalls() { |
| return numDestructorCalls; |
| } |
| |
| friend bool operator==(const Constructable & c0, const Constructable & c1) { |
| return c0.getValue() == c1.getValue(); |
| } |
| |
| friend bool LLVM_ATTRIBUTE_UNUSED |
| operator!=(const Constructable & c0, const Constructable & c1) { |
| return c0.getValue() != c1.getValue(); |
| } |
| }; |
| |
| int Constructable::numConstructorCalls; |
| int Constructable::numDestructorCalls; |
| int Constructable::numAssignmentCalls; |
| |
| // Test fixture class |
| class SmallVectorTest : public testing::Test { |
| protected: |
| typedef SmallVector<Constructable, 4> VectorType; |
| |
| VectorType theVector; |
| VectorType otherVector; |
| |
| void SetUp() { |
| Constructable::reset(); |
| } |
| |
| void assertEmpty(VectorType & v) { |
| // Size tests |
| EXPECT_EQ(0u, v.size()); |
| EXPECT_TRUE(v.empty()); |
| |
| // Iterator tests |
| EXPECT_TRUE(v.begin() == v.end()); |
| } |
| |
| // Assert that theVector contains the specified values, in order. |
| void assertValuesInOrder(VectorType & v, size_t size, ...) { |
| EXPECT_EQ(size, v.size()); |
| |
| va_list ap; |
| va_start(ap, size); |
| for (size_t i = 0; i < size; ++i) { |
| int value = va_arg(ap, int); |
| EXPECT_EQ(value, v[i].getValue()); |
| } |
| |
| va_end(ap); |
| } |
| |
| // Generate a sequence of values to initialize the vector. |
| void makeSequence(VectorType & v, int start, int end) { |
| for (int i = start; i <= end; ++i) { |
| v.push_back(Constructable(i)); |
| } |
| } |
| }; |
| |
| // New vector test. |
| TEST_F(SmallVectorTest, EmptyVectorTest) { |
| SCOPED_TRACE("EmptyVectorTest"); |
| assertEmpty(theVector); |
| EXPECT_TRUE(theVector.rbegin() == theVector.rend()); |
| EXPECT_EQ(0, Constructable::getNumConstructorCalls()); |
| EXPECT_EQ(0, Constructable::getNumDestructorCalls()); |
| } |
| |
| // Simple insertions and deletions. |
| TEST_F(SmallVectorTest, PushPopTest) { |
| SCOPED_TRACE("PushPopTest"); |
| |
| // Push an element |
| theVector.push_back(Constructable(1)); |
| |
| // Size tests |
| assertValuesInOrder(theVector, 1u, 1); |
| EXPECT_FALSE(theVector.begin() == theVector.end()); |
| EXPECT_FALSE(theVector.empty()); |
| |
| // Push another element |
| theVector.push_back(Constructable(2)); |
| assertValuesInOrder(theVector, 2u, 1, 2); |
| |
| // Insert at beginning |
| theVector.insert(theVector.begin(), theVector[1]); |
| assertValuesInOrder(theVector, 3u, 2, 1, 2); |
| |
| // Pop one element |
| theVector.pop_back(); |
| assertValuesInOrder(theVector, 2u, 2, 1); |
| |
| // Pop remaining elements |
| theVector.pop_back(); |
| theVector.pop_back(); |
| assertEmpty(theVector); |
| |
| // Check number of constructor calls. Should be 2 for each list element, |
| // one for the argument to push_back, one for the argument to insert, |
| // and one for the list element itself. |
| EXPECT_EQ(5, Constructable::getNumConstructorCalls()); |
| EXPECT_EQ(5, Constructable::getNumDestructorCalls()); |
| } |
| |
| // Clear test. |
| TEST_F(SmallVectorTest, ClearTest) { |
| SCOPED_TRACE("ClearTest"); |
| |
| makeSequence(theVector, 1, 2); |
| theVector.clear(); |
| |
| assertEmpty(theVector); |
| EXPECT_EQ(4, Constructable::getNumConstructorCalls()); |
| EXPECT_EQ(4, Constructable::getNumDestructorCalls()); |
| } |
| |
| // Resize smaller test. |
| TEST_F(SmallVectorTest, ResizeShrinkTest) { |
| SCOPED_TRACE("ResizeShrinkTest"); |
| |
| makeSequence(theVector, 1, 3); |
| theVector.resize(1); |
| |
| assertValuesInOrder(theVector, 1u, 1); |
| EXPECT_EQ(6, Constructable::getNumConstructorCalls()); |
| EXPECT_EQ(5, Constructable::getNumDestructorCalls()); |
| } |
| |
| // Resize bigger test. |
| TEST_F(SmallVectorTest, ResizeGrowTest) { |
| SCOPED_TRACE("ResizeGrowTest"); |
| |
| theVector.resize(2); |
| |
| // The extra constructor/destructor calls come from the temporary object used |
| // to initialize the contents of the resized array (via copy construction). |
| EXPECT_EQ(3, Constructable::getNumConstructorCalls()); |
| EXPECT_EQ(1, Constructable::getNumDestructorCalls()); |
| EXPECT_EQ(2u, theVector.size()); |
| } |
| |
| // Resize with fill value. |
| TEST_F(SmallVectorTest, ResizeFillTest) { |
| SCOPED_TRACE("ResizeFillTest"); |
| |
| theVector.resize(3, Constructable(77)); |
| assertValuesInOrder(theVector, 3u, 77, 77, 77); |
| } |
| |
| // Overflow past fixed size. |
| TEST_F(SmallVectorTest, OverflowTest) { |
| SCOPED_TRACE("OverflowTest"); |
| |
| // Push more elements than the fixed size. |
| makeSequence(theVector, 1, 10); |
| |
| // Test size and values. |
| EXPECT_EQ(10u, theVector.size()); |
| for (int i = 0; i < 10; ++i) { |
| EXPECT_EQ(i+1, theVector[i].getValue()); |
| } |
| |
| // Now resize back to fixed size. |
| theVector.resize(1); |
| |
| assertValuesInOrder(theVector, 1u, 1); |
| } |
| |
| // Iteration tests. |
| TEST_F(SmallVectorTest, IterationTest) { |
| makeSequence(theVector, 1, 2); |
| |
| // Forward Iteration |
| VectorType::iterator it = theVector.begin(); |
| EXPECT_TRUE(*it == theVector.front()); |
| EXPECT_TRUE(*it == theVector[0]); |
| EXPECT_EQ(1, it->getValue()); |
| ++it; |
| EXPECT_TRUE(*it == theVector[1]); |
| EXPECT_TRUE(*it == theVector.back()); |
| EXPECT_EQ(2, it->getValue()); |
| ++it; |
| EXPECT_TRUE(it == theVector.end()); |
| --it; |
| EXPECT_TRUE(*it == theVector[1]); |
| EXPECT_EQ(2, it->getValue()); |
| --it; |
| EXPECT_TRUE(*it == theVector[0]); |
| EXPECT_EQ(1, it->getValue()); |
| |
| // Reverse Iteration |
| VectorType::reverse_iterator rit = theVector.rbegin(); |
| EXPECT_TRUE(*rit == theVector[1]); |
| EXPECT_EQ(2, rit->getValue()); |
| ++rit; |
| EXPECT_TRUE(*rit == theVector[0]); |
| EXPECT_EQ(1, rit->getValue()); |
| ++rit; |
| EXPECT_TRUE(rit == theVector.rend()); |
| --rit; |
| EXPECT_TRUE(*rit == theVector[0]); |
| EXPECT_EQ(1, rit->getValue()); |
| --rit; |
| EXPECT_TRUE(*rit == theVector[1]); |
| EXPECT_EQ(2, rit->getValue()); |
| } |
| |
| // Swap test. |
| TEST_F(SmallVectorTest, SwapTest) { |
| SCOPED_TRACE("SwapTest"); |
| |
| makeSequence(theVector, 1, 2); |
| std::swap(theVector, otherVector); |
| |
| assertEmpty(theVector); |
| assertValuesInOrder(otherVector, 2u, 1, 2); |
| } |
| |
| // Append test |
| TEST_F(SmallVectorTest, AppendTest) { |
| SCOPED_TRACE("AppendTest"); |
| |
| makeSequence(otherVector, 2, 3); |
| |
| theVector.push_back(Constructable(1)); |
| theVector.append(otherVector.begin(), otherVector.end()); |
| |
| assertValuesInOrder(theVector, 3u, 1, 2, 3); |
| } |
| |
| // Append repeated test |
| TEST_F(SmallVectorTest, AppendRepeatedTest) { |
| SCOPED_TRACE("AppendRepeatedTest"); |
| |
| theVector.push_back(Constructable(1)); |
| theVector.append(2, Constructable(77)); |
| assertValuesInOrder(theVector, 3u, 1, 77, 77); |
| } |
| |
| // Assign test |
| TEST_F(SmallVectorTest, AssignTest) { |
| SCOPED_TRACE("AssignTest"); |
| |
| theVector.push_back(Constructable(1)); |
| theVector.assign(2, Constructable(77)); |
| assertValuesInOrder(theVector, 2u, 77, 77); |
| } |
| |
| // Erase a single element |
| TEST_F(SmallVectorTest, EraseTest) { |
| SCOPED_TRACE("EraseTest"); |
| |
| makeSequence(theVector, 1, 3); |
| theVector.erase(theVector.begin()); |
| assertValuesInOrder(theVector, 2u, 2, 3); |
| } |
| |
| // Erase a range of elements |
| TEST_F(SmallVectorTest, EraseRangeTest) { |
| SCOPED_TRACE("EraseRangeTest"); |
| |
| makeSequence(theVector, 1, 3); |
| theVector.erase(theVector.begin(), theVector.begin() + 2); |
| assertValuesInOrder(theVector, 1u, 3); |
| } |
| |
| // Insert a single element. |
| TEST_F(SmallVectorTest, InsertTest) { |
| SCOPED_TRACE("InsertTest"); |
| |
| makeSequence(theVector, 1, 3); |
| theVector.insert(theVector.begin() + 1, Constructable(77)); |
| assertValuesInOrder(theVector, 4u, 1, 77, 2, 3); |
| } |
| |
| // Insert repeated elements. |
| TEST_F(SmallVectorTest, InsertRepeatedTest) { |
| SCOPED_TRACE("InsertRepeatedTest"); |
| |
| makeSequence(theVector, 10, 15); |
| theVector.insert(theVector.begin() + 1, 2, Constructable(16)); |
| assertValuesInOrder(theVector, 8u, 10, 16, 16, 11, 12, 13, 14, 15); |
| } |
| |
| // Insert range. |
| TEST_F(SmallVectorTest, InsertRangeTest) { |
| SCOPED_TRACE("InsertRepeatedTest"); |
| |
| makeSequence(theVector, 1, 3); |
| theVector.insert(theVector.begin() + 1, 3, Constructable(77)); |
| assertValuesInOrder(theVector, 6u, 1, 77, 77, 77, 2, 3); |
| } |
| |
| // Comparison tests. |
| TEST_F(SmallVectorTest, ComparisonTest) { |
| SCOPED_TRACE("ComparisonTest"); |
| |
| makeSequence(theVector, 1, 3); |
| makeSequence(otherVector, 1, 3); |
| |
| EXPECT_TRUE(theVector == otherVector); |
| EXPECT_FALSE(theVector != otherVector); |
| |
| otherVector.clear(); |
| makeSequence(otherVector, 2, 4); |
| |
| EXPECT_FALSE(theVector == otherVector); |
| EXPECT_TRUE(theVector != otherVector); |
| } |
| |
| // Constant vector tests. |
| TEST_F(SmallVectorTest, ConstVectorTest) { |
| VectorType constVector; |
| |
| EXPECT_EQ(0u, constVector.size()); |
| EXPECT_TRUE(constVector.empty()); |
| EXPECT_TRUE(constVector.begin() == constVector.end()); |
| } |
| |
| // Direct array access. |
| TEST_F(SmallVectorTest, DirectVectorTest) { |
| EXPECT_EQ(0u, theVector.size()); |
| EXPECT_LE(4u, theVector.capacity()); |
| EXPECT_EQ(0, Constructable::getNumConstructorCalls()); |
| theVector.end()[0] = 1; |
| theVector.end()[1] = 2; |
| theVector.end()[2] = 3; |
| theVector.end()[3] = 4; |
| theVector.set_size(4); |
| EXPECT_EQ(4u, theVector.size()); |
| EXPECT_EQ(4, Constructable::getNumConstructorCalls()); |
| EXPECT_EQ(1, theVector[0].getValue()); |
| EXPECT_EQ(2, theVector[1].getValue()); |
| EXPECT_EQ(3, theVector[2].getValue()); |
| EXPECT_EQ(4, theVector[3].getValue()); |
| } |
| |
| TEST_F(SmallVectorTest, IteratorTest) { |
| std::list<int> L; |
| theVector.insert(theVector.end(), L.begin(), L.end()); |
| } |
| |
| } |