243 lines
5.8 KiB
C++
243 lines
5.8 KiB
C++
|
//===- unittests/ADT/BumpPtrListTest.cpp - BumpPtrList unit tests ---------===//
|
||
|
//
|
||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "llvm/ADT/AllocatorList.h"
|
||
|
#include "llvm/ADT/STLExtras.h"
|
||
|
#include "gtest/gtest.h"
|
||
|
|
||
|
using namespace llvm;
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
struct CountsDestructors {
|
||
|
static unsigned NumCalls;
|
||
|
~CountsDestructors() { ++NumCalls; }
|
||
|
};
|
||
|
unsigned CountsDestructors::NumCalls = 0;
|
||
|
|
||
|
struct MoveOnly {
|
||
|
int V;
|
||
|
explicit MoveOnly(int V) : V(V) {}
|
||
|
MoveOnly() = delete;
|
||
|
MoveOnly(MoveOnly &&X) { V = X.V; }
|
||
|
MoveOnly(const MoveOnly &X) = delete;
|
||
|
MoveOnly &operator=(MoveOnly &&X) = delete;
|
||
|
MoveOnly &operator=(const MoveOnly &X) = delete;
|
||
|
};
|
||
|
|
||
|
struct EmplaceOnly {
|
||
|
int V1, V2;
|
||
|
explicit EmplaceOnly(int V1, int V2) : V1(V1), V2(V2) {}
|
||
|
EmplaceOnly() = delete;
|
||
|
EmplaceOnly(EmplaceOnly &&X) = delete;
|
||
|
EmplaceOnly(const EmplaceOnly &X) = delete;
|
||
|
EmplaceOnly &operator=(EmplaceOnly &&X) = delete;
|
||
|
EmplaceOnly &operator=(const EmplaceOnly &X) = delete;
|
||
|
};
|
||
|
|
||
|
TEST(BumpPtrListTest, DefaultConstructor) {
|
||
|
BumpPtrList<int> L;
|
||
|
EXPECT_TRUE(L.empty());
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, pushPopBack) {
|
||
|
// Build a list with push_back.
|
||
|
BumpPtrList<int> L;
|
||
|
int Ns[] = {1, 3, 9, 5, 7};
|
||
|
for (const int N : Ns)
|
||
|
L.push_back(N);
|
||
|
|
||
|
// Use iterators to check contents.
|
||
|
auto I = L.begin();
|
||
|
for (int N : Ns)
|
||
|
EXPECT_EQ(N, *I++);
|
||
|
EXPECT_EQ(I, L.end());
|
||
|
|
||
|
// Unbuild the list with pop_back.
|
||
|
for (int N : llvm::reverse(Ns)) {
|
||
|
EXPECT_EQ(N, L.back());
|
||
|
L.pop_back();
|
||
|
}
|
||
|
EXPECT_TRUE(L.empty());
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, pushPopFront) {
|
||
|
// Build a list with push_front.
|
||
|
BumpPtrList<int> L;
|
||
|
int Ns[] = {1, 3, 9, 5, 7};
|
||
|
for (const int N : Ns)
|
||
|
L.push_front(N);
|
||
|
|
||
|
// Use reverse iterators to check contents.
|
||
|
auto I = L.rbegin();
|
||
|
for (int N : Ns)
|
||
|
EXPECT_EQ(N, *I++);
|
||
|
EXPECT_EQ(I, L.rend());
|
||
|
|
||
|
// Unbuild the list with pop_front.
|
||
|
for (int N : llvm::reverse(Ns)) {
|
||
|
EXPECT_EQ(N, L.front());
|
||
|
L.pop_front();
|
||
|
}
|
||
|
EXPECT_TRUE(L.empty());
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, pushBackMoveOnly) {
|
||
|
BumpPtrList<MoveOnly> L;
|
||
|
int Ns[] = {1, 3, 9, 5, 7};
|
||
|
for (const int N : Ns) {
|
||
|
L.push_back(MoveOnly(N));
|
||
|
EXPECT_EQ(N, L.back().V);
|
||
|
}
|
||
|
// Instantiate with MoveOnly.
|
||
|
while (!L.empty())
|
||
|
L.pop_back();
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, pushFrontMoveOnly) {
|
||
|
BumpPtrList<MoveOnly> L;
|
||
|
int Ns[] = {1, 3, 9, 5, 7};
|
||
|
for (const int N : Ns) {
|
||
|
L.push_front(MoveOnly(N));
|
||
|
EXPECT_EQ(N, L.front().V);
|
||
|
}
|
||
|
// Instantiate with MoveOnly.
|
||
|
while (!L.empty())
|
||
|
L.pop_front();
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, emplaceBack) {
|
||
|
BumpPtrList<EmplaceOnly> L;
|
||
|
int N1s[] = {1, 3, 9, 5, 7};
|
||
|
int N2s[] = {7, 3, 1, 8, 2};
|
||
|
for (int I = 0; I != 5; ++I) {
|
||
|
L.emplace_back(N1s[I], N2s[I]);
|
||
|
EXPECT_EQ(N1s[I], L.back().V1);
|
||
|
EXPECT_EQ(N2s[I], L.back().V2);
|
||
|
}
|
||
|
// Instantiate with EmplaceOnly.
|
||
|
while (!L.empty())
|
||
|
L.pop_back();
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, emplaceFront) {
|
||
|
BumpPtrList<EmplaceOnly> L;
|
||
|
int N1s[] = {1, 3, 9, 5, 7};
|
||
|
int N2s[] = {7, 3, 1, 8, 2};
|
||
|
for (int I = 0; I != 5; ++I) {
|
||
|
L.emplace_front(N1s[I], N2s[I]);
|
||
|
EXPECT_EQ(N1s[I], L.front().V1);
|
||
|
EXPECT_EQ(N2s[I], L.front().V2);
|
||
|
}
|
||
|
// Instantiate with EmplaceOnly.
|
||
|
while (!L.empty())
|
||
|
L.pop_front();
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, swap) {
|
||
|
// Build two lists with different lifetimes and swap them.
|
||
|
int N1s[] = {1, 3, 5, 7, 9};
|
||
|
int N2s[] = {2, 4, 6, 8, 10};
|
||
|
|
||
|
BumpPtrList<int> L1;
|
||
|
L1.insert(L1.end(), std::begin(N1s), std::end(N1s));
|
||
|
{
|
||
|
BumpPtrList<int> L2;
|
||
|
L2.insert(L2.end(), std::begin(N2s), std::end(N2s));
|
||
|
|
||
|
// Swap the lists.
|
||
|
L1.swap(L2);
|
||
|
|
||
|
// Check L2's contents before it goes out of scope.
|
||
|
auto I = L2.begin();
|
||
|
for (int N : N1s)
|
||
|
EXPECT_EQ(N, *I++);
|
||
|
EXPECT_EQ(I, L2.end());
|
||
|
}
|
||
|
|
||
|
// Check L1's contents now that L2 is out of scope (with its allocation
|
||
|
// blocks).
|
||
|
auto I = L1.begin();
|
||
|
for (int N : N2s)
|
||
|
EXPECT_EQ(N, *I++);
|
||
|
EXPECT_EQ(I, L1.end());
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, clear) {
|
||
|
CountsDestructors::NumCalls = 0;
|
||
|
CountsDestructors N;
|
||
|
BumpPtrList<CountsDestructors> L;
|
||
|
L.push_back(N);
|
||
|
L.push_back(N);
|
||
|
L.push_back(N);
|
||
|
EXPECT_EQ(3u, L.size());
|
||
|
EXPECT_EQ(0u, CountsDestructors::NumCalls);
|
||
|
L.pop_back();
|
||
|
EXPECT_EQ(1u, CountsDestructors::NumCalls);
|
||
|
L.clear();
|
||
|
EXPECT_EQ(3u, CountsDestructors::NumCalls);
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, move) {
|
||
|
BumpPtrList<int> L1, L2;
|
||
|
L1.push_back(1);
|
||
|
L2.push_back(2);
|
||
|
L1 = std::move(L2);
|
||
|
EXPECT_EQ(1u, L1.size());
|
||
|
EXPECT_EQ(2, L1.front());
|
||
|
EXPECT_EQ(0u, L2.size());
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, moveCallsDestructors) {
|
||
|
CountsDestructors::NumCalls = 0;
|
||
|
BumpPtrList<CountsDestructors> L1, L2;
|
||
|
L1.emplace_back();
|
||
|
EXPECT_EQ(0u, CountsDestructors::NumCalls);
|
||
|
L1 = std::move(L2);
|
||
|
EXPECT_EQ(1u, CountsDestructors::NumCalls);
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, copy) {
|
||
|
BumpPtrList<int> L1, L2;
|
||
|
L1.push_back(1);
|
||
|
L2.push_back(2);
|
||
|
L1 = L2;
|
||
|
EXPECT_EQ(1u, L1.size());
|
||
|
EXPECT_EQ(2, L1.front());
|
||
|
EXPECT_EQ(1u, L2.size());
|
||
|
EXPECT_EQ(2, L2.front());
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, copyCallsDestructors) {
|
||
|
CountsDestructors::NumCalls = 0;
|
||
|
BumpPtrList<CountsDestructors> L1, L2;
|
||
|
L1.emplace_back();
|
||
|
EXPECT_EQ(0u, CountsDestructors::NumCalls);
|
||
|
L1 = L2;
|
||
|
EXPECT_EQ(1u, CountsDestructors::NumCalls);
|
||
|
}
|
||
|
|
||
|
TEST(BumpPtrListTest, resetAlloc) {
|
||
|
// Resetting an empty list should work.
|
||
|
BumpPtrList<int> L;
|
||
|
|
||
|
// Resetting an empty list that has allocated should also work.
|
||
|
L.resetAlloc();
|
||
|
L.push_back(5);
|
||
|
L.erase(L.begin());
|
||
|
L.resetAlloc();
|
||
|
|
||
|
// Resetting a non-empty list should crash.
|
||
|
L.push_back(5);
|
||
|
#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
|
||
|
EXPECT_DEATH(L.resetAlloc(), "Cannot reset allocator if not empty");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
} // end namespace
|