mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
1af3e8d9df
- Add AllocatorList, a non-intrusive list that owns an LLVM-style allocator and provides a std::list-like interface (trivially built on top of simple_ilist), - add a typedef (and unit tests) for BumpPtrList, and - use BumpPtrList for the list of llvm::yaml::Token (i.e., TokenQueueT). TokenQueueT has no need for the complexity of an intrusive list. The only reason to inherit from ilist was to customize the allocator. TokenQueueT was the only example in-tree of using ilist<> in a truly non-intrusive way. Moreover, this removes the final use of the non-intrusive ilist_traits<>::createNode (after r280573, r281177, and r281181). I have a WIP patch that removes this customization point (and the API that relies on it) that I plan to commit soon. Note: AllocatorList owns the allocator, which limits the viable API (e.g., splicing must be on the same list). For now I've left out any problematic API. It wouldn't be hard to split AllocatorList into two layers: an Impl class that calls DerivedT::getAlloc (via CRTP), and derived classes that handle Allocator ownership/reference/etc semantics; and then implement splice with appropriate assertions; but TBH we should probably just customize the std::list allocators at that point. llvm-svn: 281182
244 lines
5.8 KiB
C++
244 lines
5.8 KiB
C++
//===- unittests/ADT/BumpPtrListTest.cpp - BumpPtrList unit tests ---------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#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
|