blob: 0dee4c10f68f65d714dffab9def6a6cb57ce4e0f [file] [log] [blame]
Duncan P. N. Exon Smithfbdb2012016-08-30 00:18:43 +00001//===- unittests/ADT/IListTest.cpp - ilist unit tests ---------------------===//
Daniel Dunbar959ae592010-05-12 21:35:19 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Daniel Dunbar959ae592010-05-12 21:35:19 +000010#include "llvm/ADT/ilist.h"
Jakob Stoklund Olesenb8d29bf2012-12-18 19:28:37 +000011#include "llvm/ADT/STLExtras.h"
Chandler Carruthb034cb72013-01-02 10:26:28 +000012#include "llvm/ADT/ilist_node.h"
Chandler Carruth130cec22012-12-04 10:23:08 +000013#include "gtest/gtest.h"
14#include <ostream>
Daniel Dunbar959ae592010-05-12 21:35:19 +000015
16using namespace llvm;
17
18namespace {
19
20struct Node : ilist_node<Node> {
21 int Value;
22
23 Node() {}
David Blaikie0bc56da2015-03-04 17:01:18 +000024 Node(int Value) : Value(Value) {}
25 Node(const Node&) = default;
Jakob Stoklund Olesen4ccabc12013-01-04 22:35:42 +000026 ~Node() { Value = -1; }
Daniel Dunbar959ae592010-05-12 21:35:19 +000027};
28
Duncan P. N. Exon Smithfbdb2012016-08-30 00:18:43 +000029TEST(IListTest, Basic) {
Daniel Dunbar959ae592010-05-12 21:35:19 +000030 ilist<Node> List;
Duncan P. N. Exon Smithb5da0052016-09-11 23:43:43 +000031 List.push_back(new Node(1));
Daniel Dunbar959ae592010-05-12 21:35:19 +000032 EXPECT_EQ(1, List.back().Value);
Duncan P. N. Exon Smith4042d912015-11-11 02:26:42 +000033 EXPECT_EQ(nullptr, List.getPrevNode(List.back()));
34 EXPECT_EQ(nullptr, List.getNextNode(List.back()));
Daniel Dunbar959ae592010-05-12 21:35:19 +000035
Duncan P. N. Exon Smithb5da0052016-09-11 23:43:43 +000036 List.push_back(new Node(2));
Daniel Dunbar959ae592010-05-12 21:35:19 +000037 EXPECT_EQ(2, List.back().Value);
Duncan P. N. Exon Smith4042d912015-11-11 02:26:42 +000038 EXPECT_EQ(2, List.getNextNode(List.front())->Value);
39 EXPECT_EQ(1, List.getPrevNode(List.back())->Value);
Daniel Dunbar2842f252010-05-13 18:35:02 +000040
41 const ilist<Node> &ConstList = List;
42 EXPECT_EQ(2, ConstList.back().Value);
Duncan P. N. Exon Smith4042d912015-11-11 02:26:42 +000043 EXPECT_EQ(2, ConstList.getNextNode(ConstList.front())->Value);
44 EXPECT_EQ(1, ConstList.getPrevNode(ConstList.back())->Value);
Daniel Dunbar959ae592010-05-12 21:35:19 +000045}
46
Duncan P. N. Exon Smithb5da0052016-09-11 23:43:43 +000047TEST(IListTest, cloneFrom) {
48 Node L1Nodes[] = {Node(0), Node(1)};
49 Node L2Nodes[] = {Node(0), Node(1)};
50 ilist<Node> L1, L2, L3;
51
52 // Build L1 from L1Nodes.
53 L1.push_back(&L1Nodes[0]);
54 L1.push_back(&L1Nodes[1]);
55
56 // Build L2 from L2Nodes, based on L1 nodes.
57 L2.cloneFrom(L1, [&](const Node &N) { return &L2Nodes[N.Value]; });
58
59 // Add a node to L3 to be deleted, and then rebuild L3 by copying L1.
60 L3.push_back(new Node(7));
61 L3.cloneFrom(L1, [](const Node &N) { return new Node(N); });
62
63 EXPECT_EQ(2u, L1.size());
64 EXPECT_EQ(&L1Nodes[0], &L1.front());
65 EXPECT_EQ(&L1Nodes[1], &L1.back());
66 EXPECT_EQ(2u, L2.size());
67 EXPECT_EQ(&L2Nodes[0], &L2.front());
68 EXPECT_EQ(&L2Nodes[1], &L2.back());
69 EXPECT_EQ(2u, L3.size());
70 EXPECT_EQ(0, L3.front().Value);
71 EXPECT_EQ(1, L3.back().Value);
72
73 // Don't free nodes on the stack.
74 L1.clearAndLeakNodesUnsafely();
75 L2.clearAndLeakNodesUnsafely();
76}
77
Duncan P. N. Exon Smithfbdb2012016-08-30 00:18:43 +000078TEST(IListTest, SpliceOne) {
Jakob Stoklund Olesenb8d29bf2012-12-18 19:28:37 +000079 ilist<Node> List;
Duncan P. N. Exon Smithb5da0052016-09-11 23:43:43 +000080 List.push_back(new Node(1));
Jakob Stoklund Olesenb8d29bf2012-12-18 19:28:37 +000081
82 // The single-element splice operation supports noops.
83 List.splice(List.begin(), List, List.begin());
84 EXPECT_EQ(1u, List.size());
85 EXPECT_EQ(1, List.front().Value);
Benjamin Kramerb6d0bd42014-03-02 12:27:27 +000086 EXPECT_TRUE(std::next(List.begin()) == List.end());
Jakob Stoklund Olesenb8d29bf2012-12-18 19:28:37 +000087
88 // Altenative noop. Move the first element behind itself.
Duncan P. N. Exon Smithb5da0052016-09-11 23:43:43 +000089 List.push_back(new Node(2));
90 List.push_back(new Node(3));
Benjamin Kramerb6d0bd42014-03-02 12:27:27 +000091 List.splice(std::next(List.begin()), List, List.begin());
Jakob Stoklund Olesenb8d29bf2012-12-18 19:28:37 +000092 EXPECT_EQ(3u, List.size());
93 EXPECT_EQ(1, List.front().Value);
Benjamin Kramerb6d0bd42014-03-02 12:27:27 +000094 EXPECT_EQ(2, std::next(List.begin())->Value);
Jakob Stoklund Olesenb8d29bf2012-12-18 19:28:37 +000095 EXPECT_EQ(3, List.back().Value);
96}
97
Duncan P. N. Exon Smithfbdb2012016-08-30 00:18:43 +000098TEST(IListTest, SpliceSwap) {
Duncan P. N. Exon Smith47416612016-08-17 02:08:08 +000099 ilist<Node> L;
100 Node N0(0);
101 Node N1(1);
102 L.insert(L.end(), &N0);
103 L.insert(L.end(), &N1);
104 EXPECT_EQ(0, L.front().Value);
105 EXPECT_EQ(1, L.back().Value);
106
107 L.splice(L.begin(), L, ++L.begin());
108 EXPECT_EQ(1, L.front().Value);
109 EXPECT_EQ(0, L.back().Value);
110
111 L.clearAndLeakNodesUnsafely();
112}
113
Duncan P. N. Exon Smithfbdb2012016-08-30 00:18:43 +0000114TEST(IListTest, SpliceSwapOtherWay) {
Duncan P. N. Exon Smith47416612016-08-17 02:08:08 +0000115 ilist<Node> L;
116 Node N0(0);
117 Node N1(1);
118 L.insert(L.end(), &N0);
119 L.insert(L.end(), &N1);
120 EXPECT_EQ(0, L.front().Value);
121 EXPECT_EQ(1, L.back().Value);
122
123 L.splice(L.end(), L, L.begin());
124 EXPECT_EQ(1, L.front().Value);
125 EXPECT_EQ(0, L.back().Value);
126
127 L.clearAndLeakNodesUnsafely();
128}
129
Duncan P. N. Exon Smithfbdb2012016-08-30 00:18:43 +0000130TEST(IListTest, UnsafeClear) {
Jakob Stoklund Olesen4ccabc12013-01-04 22:35:42 +0000131 ilist<Node> List;
132
133 // Before even allocating a sentinel.
134 List.clearAndLeakNodesUnsafely();
135 EXPECT_EQ(0u, List.size());
136
137 // Empty list with sentinel.
138 ilist<Node>::iterator E = List.end();
139 List.clearAndLeakNodesUnsafely();
140 EXPECT_EQ(0u, List.size());
141 // The sentinel shouldn't change.
142 EXPECT_TRUE(E == List.end());
143
144 // List with contents.
Duncan P. N. Exon Smithb5da0052016-09-11 23:43:43 +0000145 List.push_back(new Node(1));
Jakob Stoklund Olesen4ccabc12013-01-04 22:35:42 +0000146 ASSERT_EQ(1u, List.size());
Duncan P. N. Exon Smithc8925b12015-10-20 18:30:20 +0000147 Node *N = &*List.begin();
Jakob Stoklund Olesen4ccabc12013-01-04 22:35:42 +0000148 EXPECT_EQ(1, N->Value);
149 List.clearAndLeakNodesUnsafely();
150 EXPECT_EQ(0u, List.size());
151 ASSERT_EQ(1, N->Value);
152 delete N;
153
154 // List is still functional.
Duncan P. N. Exon Smithb5da0052016-09-11 23:43:43 +0000155 List.push_back(new Node(5));
156 List.push_back(new Node(6));
Jakob Stoklund Olesen4ccabc12013-01-04 22:35:42 +0000157 ASSERT_EQ(2u, List.size());
158 EXPECT_EQ(5, List.front().Value);
159 EXPECT_EQ(6, List.back().Value);
160}
161
Duncan P. N. Exon Smith11cb5382016-08-19 20:17:23 +0000162struct Empty {};
Duncan P. N. Exon Smithfbdb2012016-08-30 00:18:43 +0000163TEST(IListTest, HasObsoleteCustomizationTrait) {
Duncan P. N. Exon Smith11cb5382016-08-19 20:17:23 +0000164 // Negative test for HasObsoleteCustomization.
165 static_assert(!ilist_detail::HasObsoleteCustomization<Empty, Node>::value,
166 "Empty has no customizations");
Daniel Dunbar959ae592010-05-12 21:35:19 +0000167}
Duncan P. N. Exon Smith11cb5382016-08-19 20:17:23 +0000168
169struct GetNext {
170 Node *getNext(Node *);
171};
Duncan P. N. Exon Smithfbdb2012016-08-30 00:18:43 +0000172TEST(IListTest, HasGetNextTrait) {
Duncan P. N. Exon Smith11cb5382016-08-19 20:17:23 +0000173 static_assert(ilist_detail::HasGetNext<GetNext, Node>::value,
174 "GetNext has a getNext(Node*)");
175 static_assert(ilist_detail::HasObsoleteCustomization<GetNext, Node>::value,
176 "Empty should be obsolete because of getNext()");
177
178 // Negative test for HasGetNext.
179 static_assert(!ilist_detail::HasGetNext<Empty, Node>::value,
180 "Empty does not have a getNext(Node*)");
181}
182
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000183struct CreateSentinel {
184 Node *createSentinel();
185};
Duncan P. N. Exon Smithfbdb2012016-08-30 00:18:43 +0000186TEST(IListTest, HasCreateSentinelTrait) {
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000187 static_assert(ilist_detail::HasCreateSentinel<CreateSentinel>::value,
188 "CreateSentinel has a getNext(Node*)");
189 static_assert(
190 ilist_detail::HasObsoleteCustomization<CreateSentinel, Node>::value,
191 "Empty should be obsolete because of createSentinel()");
192
193 // Negative test for HasCreateSentinel.
194 static_assert(!ilist_detail::HasCreateSentinel<Empty>::value,
195 "Empty does not have a createSentinel()");
196}
197
198struct NodeWithCallback : ilist_node<NodeWithCallback> {
199 int Value = 0;
200 bool IsInList = false;
Duncan P. N. Exon Smithf947c3a2016-08-30 18:40:47 +0000201 bool WasTransferred = false;
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000202
203 NodeWithCallback() = default;
204 NodeWithCallback(int Value) : Value(Value) {}
205 NodeWithCallback(const NodeWithCallback &) = delete;
206};
207
208} // end namespace
209
210namespace llvm {
Duncan P. N. Exon Smithf947c3a2016-08-30 18:40:47 +0000211template <> struct ilist_callback_traits<NodeWithCallback> {
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000212 void addNodeToList(NodeWithCallback *N) { N->IsInList = true; }
213 void removeNodeFromList(NodeWithCallback *N) { N->IsInList = false; }
Duncan P. N. Exon Smithf947c3a2016-08-30 18:40:47 +0000214 template <class Iterator>
215 void transferNodesFromList(ilist_callback_traits &Other, Iterator First,
216 Iterator Last) {
217 for (; First != Last; ++First) {
218 First->WasTransferred = true;
219 Other.removeNodeFromList(&*First);
220 addNodeToList(&*First);
221 }
222 }
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000223};
224} // end namespace llvm
225
226namespace {
227
Duncan P. N. Exon Smithfbdb2012016-08-30 00:18:43 +0000228TEST(IListTest, addNodeToList) {
Duncan P. N. Exon Smithf947c3a2016-08-30 18:40:47 +0000229 ilist<NodeWithCallback> L1, L2;
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000230 NodeWithCallback N(7);
231 ASSERT_FALSE(N.IsInList);
Duncan P. N. Exon Smithf947c3a2016-08-30 18:40:47 +0000232 ASSERT_FALSE(N.WasTransferred);
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000233
Duncan P. N. Exon Smithf947c3a2016-08-30 18:40:47 +0000234 L1.insert(L1.begin(), &N);
235 ASSERT_EQ(1u, L1.size());
236 ASSERT_EQ(&N, &L1.front());
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000237 ASSERT_TRUE(N.IsInList);
Duncan P. N. Exon Smithf947c3a2016-08-30 18:40:47 +0000238 ASSERT_FALSE(N.WasTransferred);
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000239
Duncan P. N. Exon Smithf947c3a2016-08-30 18:40:47 +0000240 L2.splice(L2.end(), L1);
241 ASSERT_EQ(&N, &L2.front());
242 ASSERT_TRUE(N.IsInList);
243 ASSERT_TRUE(N.WasTransferred);
244
245 L1.remove(&N);
246 ASSERT_EQ(0u, L1.size());
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000247 ASSERT_FALSE(N.IsInList);
Duncan P. N. Exon Smithf947c3a2016-08-30 18:40:47 +0000248 ASSERT_TRUE(N.WasTransferred);
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000249}
250
251struct PrivateNode : private ilist_node<PrivateNode> {
Duncan P. N. Exon Smith34c4d2a2016-09-10 16:55:06 +0000252 friend struct llvm::ilist_detail::NodeAccess;
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000253
254 int Value = 0;
255
256 PrivateNode() = default;
257 PrivateNode(int Value) : Value(Value) {}
258 PrivateNode(const PrivateNode &) = delete;
259};
260
Duncan P. N. Exon Smithfbdb2012016-08-30 00:18:43 +0000261TEST(IListTest, privateNode) {
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000262 // Instantiate various APIs to be sure they're callable when ilist_node is
263 // inherited privately.
Duncan P. N. Exon Smithe974f572016-09-03 01:06:08 +0000264 ilist<PrivateNode> L;
265 PrivateNode N(7);
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000266 L.insert(L.begin(), &N);
267 ++L.begin();
268 (void)*L.begin();
269 (void)(L.begin() == L.end());
270
Duncan P. N. Exon Smithe974f572016-09-03 01:06:08 +0000271 ilist<PrivateNode> L2;
Duncan P. N. Exon Smith64093a32016-08-19 20:40:12 +0000272 L2.splice(L2.end(), L);
273 L2.remove(&N);
274}
275
Duncan P. N. Exon Smith11cb5382016-08-19 20:17:23 +0000276} // end namespace