1 //===- unittests/ADT/IListTest.cpp - ilist unit tests ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/ADT/ilist.h"
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/ADT/ilist_node.h"
13 #include "gtest/gtest.h"
20 struct Node
: ilist_node
<Node
> {
24 Node(int Value
) : Value(Value
) {}
25 Node(const Node
&) = default;
26 ~Node() { Value
= -1; }
29 TEST(IListTest
, Basic
) {
31 List
.push_back(new Node(1));
32 EXPECT_EQ(1, List
.back().Value
);
33 EXPECT_EQ(nullptr, List
.getPrevNode(List
.back()));
34 EXPECT_EQ(nullptr, List
.getNextNode(List
.back()));
36 List
.push_back(new Node(2));
37 EXPECT_EQ(2, List
.back().Value
);
38 EXPECT_EQ(2, List
.getNextNode(List
.front())->Value
);
39 EXPECT_EQ(1, List
.getPrevNode(List
.back())->Value
);
41 const ilist
<Node
> &ConstList
= List
;
42 EXPECT_EQ(2, ConstList
.back().Value
);
43 EXPECT_EQ(2, ConstList
.getNextNode(ConstList
.front())->Value
);
44 EXPECT_EQ(1, ConstList
.getPrevNode(ConstList
.back())->Value
);
47 TEST(IListTest
, cloneFrom
) {
48 Node L1Nodes
[] = {Node(0), Node(1)};
49 Node L2Nodes
[] = {Node(0), Node(1)};
50 ilist
<Node
> L1
, L2
, L3
;
52 // Build L1 from L1Nodes.
53 L1
.push_back(&L1Nodes
[0]);
54 L1
.push_back(&L1Nodes
[1]);
56 // Build L2 from L2Nodes, based on L1 nodes.
57 L2
.cloneFrom(L1
, [&](const Node
&N
) { return &L2Nodes
[N
.Value
]; });
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
); });
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
);
73 // Don't free nodes on the stack.
74 L1
.clearAndLeakNodesUnsafely();
75 L2
.clearAndLeakNodesUnsafely();
78 TEST(IListTest
, SpliceOne
) {
80 List
.push_back(new Node(1));
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
);
86 EXPECT_TRUE(std::next(List
.begin()) == List
.end());
88 // Altenative noop. Move the first element behind itself.
89 List
.push_back(new Node(2));
90 List
.push_back(new Node(3));
91 List
.splice(std::next(List
.begin()), List
, List
.begin());
92 EXPECT_EQ(3u, List
.size());
93 EXPECT_EQ(1, List
.front().Value
);
94 EXPECT_EQ(2, std::next(List
.begin())->Value
);
95 EXPECT_EQ(3, List
.back().Value
);
98 TEST(IListTest
, SpliceSwap
) {
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
);
107 L
.splice(L
.begin(), L
, ++L
.begin());
108 EXPECT_EQ(1, L
.front().Value
);
109 EXPECT_EQ(0, L
.back().Value
);
111 L
.clearAndLeakNodesUnsafely();
114 TEST(IListTest
, SpliceSwapOtherWay
) {
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
);
123 L
.splice(L
.end(), L
, L
.begin());
124 EXPECT_EQ(1, L
.front().Value
);
125 EXPECT_EQ(0, L
.back().Value
);
127 L
.clearAndLeakNodesUnsafely();
130 TEST(IListTest
, UnsafeClear
) {
133 // Before even allocating a sentinel.
134 List
.clearAndLeakNodesUnsafely();
135 EXPECT_EQ(0u, List
.size());
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());
144 // List with contents.
145 List
.push_back(new Node(1));
146 ASSERT_EQ(1u, List
.size());
147 Node
*N
= &*List
.begin();
148 EXPECT_EQ(1, N
->Value
);
149 List
.clearAndLeakNodesUnsafely();
150 EXPECT_EQ(0u, List
.size());
151 ASSERT_EQ(1, N
->Value
);
154 // List is still functional.
155 List
.push_back(new Node(5));
156 List
.push_back(new Node(6));
157 ASSERT_EQ(2u, List
.size());
158 EXPECT_EQ(5, List
.front().Value
);
159 EXPECT_EQ(6, List
.back().Value
);
163 TEST(IListTest
, HasObsoleteCustomizationTrait
) {
164 // Negative test for HasObsoleteCustomization.
165 static_assert(!ilist_detail::HasObsoleteCustomization
<Empty
, Node
>::value
,
166 "Empty has no customizations");
170 Node
*getNext(Node
*);
172 TEST(IListTest
, HasGetNextTrait
) {
173 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()");
178 // Negative test for HasGetNext.
179 static_assert(!ilist_detail::HasGetNext
<Empty
, Node
>::value
,
180 "Empty does not have a getNext(Node*)");
183 struct CreateSentinel
{
184 Node
*createSentinel();
186 TEST(IListTest
, HasCreateSentinelTrait
) {
187 static_assert(ilist_detail::HasCreateSentinel
<CreateSentinel
>::value
,
188 "CreateSentinel has a getNext(Node*)");
190 ilist_detail::HasObsoleteCustomization
<CreateSentinel
, Node
>::value
,
191 "Empty should be obsolete because of createSentinel()");
193 // Negative test for HasCreateSentinel.
194 static_assert(!ilist_detail::HasCreateSentinel
<Empty
>::value
,
195 "Empty does not have a createSentinel()");
198 struct NodeWithCallback
: ilist_node
<NodeWithCallback
> {
200 bool IsInList
= false;
201 bool WasTransferred
= false;
203 NodeWithCallback() = default;
204 NodeWithCallback(int Value
) : Value(Value
) {}
205 NodeWithCallback(const NodeWithCallback
&) = delete;
211 template <> struct ilist_callback_traits
<NodeWithCallback
> {
212 void addNodeToList(NodeWithCallback
*N
) { N
->IsInList
= true; }
213 void removeNodeFromList(NodeWithCallback
*N
) { N
->IsInList
= false; }
214 template <class Iterator
>
215 void transferNodesFromList(ilist_callback_traits
&Other
, Iterator First
,
217 for (; First
!= Last
; ++First
) {
218 First
->WasTransferred
= true;
219 Other
.removeNodeFromList(&*First
);
220 addNodeToList(&*First
);
224 } // end namespace llvm
228 TEST(IListTest
, addNodeToList
) {
229 ilist
<NodeWithCallback
> L1
, L2
;
230 NodeWithCallback
N(7);
231 ASSERT_FALSE(N
.IsInList
);
232 ASSERT_FALSE(N
.WasTransferred
);
234 L1
.insert(L1
.begin(), &N
);
235 ASSERT_EQ(1u, L1
.size());
236 ASSERT_EQ(&N
, &L1
.front());
237 ASSERT_TRUE(N
.IsInList
);
238 ASSERT_FALSE(N
.WasTransferred
);
240 L2
.splice(L2
.end(), L1
);
241 ASSERT_EQ(&N
, &L2
.front());
242 ASSERT_TRUE(N
.IsInList
);
243 ASSERT_TRUE(N
.WasTransferred
);
246 ASSERT_EQ(0u, L1
.size());
247 ASSERT_FALSE(N
.IsInList
);
248 ASSERT_TRUE(N
.WasTransferred
);
251 struct PrivateNode
: private ilist_node
<PrivateNode
> {
252 friend struct llvm::ilist_detail::NodeAccess
;
256 PrivateNode() = default;
257 PrivateNode(int Value
) : Value(Value
) {}
258 PrivateNode(const PrivateNode
&) = delete;
261 TEST(IListTest
, privateNode
) {
262 // Instantiate various APIs to be sure they're callable when ilist_node is
263 // inherited privately.
264 ilist
<PrivateNode
> L
;
266 L
.insert(L
.begin(), &N
);
269 (void)(L
.begin() == L
.end());
271 ilist
<PrivateNode
> L2
;
272 L2
.splice(L2
.end(), L
);