1 //===- unittests/ADT/IListTest.cpp - ilist unit tests ---------------------===// 2 // 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 10 #include "llvm/ADT/ilist.h" 11 #include "llvm/ADT/STLExtras.h" 12 #include "llvm/ADT/ilist_node.h" 13 #include "gtest/gtest.h" 14 #include <ostream> 15 16 using namespace llvm; 17 18 namespace { 19 20 struct Node : ilist_node<Node> { 21 int Value; 22 23 Node() {} 24 Node(int Value) : Value(Value) {} 25 Node(const Node&) = default; 26 ~Node() { Value = -1; } 27 }; 28 29 TEST(IListTest, Basic) { 30 ilist<Node> List; 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())); 35 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); 40 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); 45 } 46 47 TEST(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 78 TEST(IListTest, SpliceOne) { 79 ilist<Node> List; 80 List.push_back(new Node(1)); 81 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()); 87 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); 96 } 97 98 TEST(IListTest, SpliceSwap) { 99 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 114 TEST(IListTest, SpliceSwapOtherWay) { 115 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 130 TEST(IListTest, UnsafeClear) { 131 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. 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); 152 delete N; 153 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); 160 } 161 162 struct Empty {}; 163 TEST(IListTest, HasObsoleteCustomizationTrait) { 164 // Negative test for HasObsoleteCustomization. 165 static_assert(!ilist_detail::HasObsoleteCustomization<Empty, Node>::value, 166 "Empty has no customizations"); 167 } 168 169 struct GetNext { 170 Node *getNext(Node *); 171 }; 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()"); 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 183 struct CreateSentinel { 184 Node *createSentinel(); 185 }; 186 TEST(IListTest, HasCreateSentinelTrait) { 187 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 198 struct NodeWithCallback : ilist_node<NodeWithCallback> { 199 int Value = 0; 200 bool IsInList = false; 201 bool WasTransferred = false; 202 203 NodeWithCallback() = default; 204 NodeWithCallback(int Value) : Value(Value) {} 205 NodeWithCallback(const NodeWithCallback &) = delete; 206 }; 207 208 } // end namespace 209 210 namespace llvm { 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, 216 Iterator Last) { 217 for (; First != Last; ++First) { 218 First->WasTransferred = true; 219 Other.removeNodeFromList(&*First); 220 addNodeToList(&*First); 221 } 222 } 223 }; 224 } // end namespace llvm 225 226 namespace { 227 228 TEST(IListTest, addNodeToList) { 229 ilist<NodeWithCallback> L1, L2; 230 NodeWithCallback N(7); 231 ASSERT_FALSE(N.IsInList); 232 ASSERT_FALSE(N.WasTransferred); 233 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); 239 240 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()); 247 ASSERT_FALSE(N.IsInList); 248 ASSERT_TRUE(N.WasTransferred); 249 } 250 251 struct PrivateNode : private ilist_node<PrivateNode> { 252 friend struct llvm::ilist_detail::NodeAccess; 253 254 int Value = 0; 255 256 PrivateNode() = default; 257 PrivateNode(int Value) : Value(Value) {} 258 PrivateNode(const PrivateNode &) = delete; 259 }; 260 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; 265 PrivateNode N(7); 266 L.insert(L.begin(), &N); 267 ++L.begin(); 268 (void)*L.begin(); 269 (void)(L.begin() == L.end()); 270 271 ilist<PrivateNode> L2; 272 L2.splice(L2.end(), L); 273 L2.remove(&N); 274 } 275 276 } // end namespace 277