From 7c5c12bd4d60070c90161df9f6ae078c1f7b1ce5 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Fri, 4 Jan 2013 22:35:42 +0000 Subject: Add an iplist::clearAndLeakNodesUnsafely() function. The iplist::clear() function can be quite expensive because it traverses the entire list, calling deleteNode() and removeNodeFromList() on each element. If node destruction and deallocation can be handled some other way, clearAndLeakNodesUnsafely() can be used to jettison all nodes without bringing them into cache. The function name is meant to be ominous. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@171540 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ADT/ilist.h | 11 +++++++++++ unittests/ADT/ilistTest.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/include/llvm/ADT/ilist.h b/include/llvm/ADT/ilist.h index 36650d4375..20cdae3255 100644 --- a/include/llvm/ADT/ilist.h +++ b/include/llvm/ADT/ilist.h @@ -465,6 +465,17 @@ public: return where; } + /// Remove all nodes from the list like clear(), but do not call + /// removeNodeFromList() or deleteNode(). + /// + /// This should only be used immediately before freeing nodes in bulk to + /// avoid traversing the list and bringing all the nodes into cache. + void clearAndLeakNodesUnsafely() { + if (Head) { + Head = getTail(); + this->setPrev(Head, Head); + } + } private: // transfer - The heart of the splice function. Move linked list nodes from diff --git a/unittests/ADT/ilistTest.cpp b/unittests/ADT/ilistTest.cpp index 07bd5ec601..0c0cd0fd56 100644 --- a/unittests/ADT/ilistTest.cpp +++ b/unittests/ADT/ilistTest.cpp @@ -22,6 +22,7 @@ struct Node : ilist_node { Node() {} Node(int _Value) : Value(_Value) {} + ~Node() { Value = -1; } }; TEST(ilistTest, Basic) { @@ -62,4 +63,36 @@ TEST(ilistTest, SpliceOne) { EXPECT_EQ(3, List.back().Value); } +TEST(ilistTest, UnsafeClear) { + ilist List; + + // Before even allocating a sentinel. + List.clearAndLeakNodesUnsafely(); + EXPECT_EQ(0u, List.size()); + + // Empty list with sentinel. + ilist::iterator E = List.end(); + List.clearAndLeakNodesUnsafely(); + EXPECT_EQ(0u, List.size()); + // The sentinel shouldn't change. + EXPECT_TRUE(E == List.end()); + + // List with contents. + List.push_back(1); + ASSERT_EQ(1u, List.size()); + Node *N = List.begin(); + EXPECT_EQ(1, N->Value); + List.clearAndLeakNodesUnsafely(); + EXPECT_EQ(0u, List.size()); + ASSERT_EQ(1, N->Value); + delete N; + + // List is still functional. + List.push_back(5); + List.push_back(6); + ASSERT_EQ(2u, List.size()); + EXPECT_EQ(5, List.front().Value); + EXPECT_EQ(6, List.back().Value); +} + } -- cgit v1.2.3-18-g5258