diff options
-rw-r--r-- | llvm/include/llvm/ADT/ilist.h | 147 | ||||
-rw-r--r-- | llvm/include/llvm/ADT/ilist_node.h | 24 | ||||
-rw-r--r-- | llvm/unittests/ADT/CMakeLists.txt | 3 | ||||
-rw-r--r-- | llvm/unittests/ADT/IListBaseTest.cpp | 102 | ||||
-rw-r--r-- | llvm/unittests/ADT/IListNodeBaseTest.cpp | 60 | ||||
-rw-r--r-- | llvm/unittests/ADT/IListSentinelTest.cpp | 37 |
6 files changed, 295 insertions, 78 deletions
diff --git a/llvm/include/llvm/ADT/ilist.h b/llvm/include/llvm/ADT/ilist.h index 04bb5608252..ef0d9f3b0d6 100644 --- a/llvm/include/llvm/ADT/ilist.h +++ b/llvm/include/llvm/ADT/ilist.h @@ -50,30 +50,19 @@ struct ilist_node_access { return N; } - template <typename T> static ilist_node<T> *getPrev(ilist_node<T> *N) { - return N->getPrev(); + template <typename T> static ilist_node<T> *getPrev(ilist_node<T> &N) { + return N.getPrev(); } - template <typename T> static ilist_node<T> *getNext(ilist_node<T> *N) { - return N->getNext(); + template <typename T> static ilist_node<T> *getNext(ilist_node<T> &N) { + return N.getNext(); } - template <typename T> static const ilist_node<T> *getPrev(const ilist_node<T> *N) { - return N->getPrev(); + template <typename T> + static const ilist_node<T> *getPrev(const ilist_node<T> &N) { + return N.getPrev(); } - template <typename T> static const ilist_node<T> *getNext(const ilist_node<T> *N) { - return N->getNext(); - } - - template <typename T> static void setPrev(ilist_node<T> *N, ilist_node<T> *Prev) { - N->setPrev(Prev); - } - template <typename T> static void setNext(ilist_node<T> *N, ilist_node<T> *Next) { - N->setNext(Next); - } - template <typename T> static void setPrev(ilist_node<T> *N, std::nullptr_t) { - N->setPrev(nullptr); - } - template <typename T> static void setNext(ilist_node<T> *N, std::nullptr_t) { - N->setNext(nullptr); + template <typename T> + static const ilist_node<T> *getNext(const ilist_node<T> &N) { + return N.getNext(); } }; @@ -228,12 +217,12 @@ public: // Increment and decrement operators... ilist_iterator &operator--() { - NodePtr = ilist_node_access::getPrev(NodePtr); + NodePtr = ilist_node_access::getPrev(*NodePtr); assert(NodePtr && "--'d off the beginning of an ilist!"); return *this; } ilist_iterator &operator++() { - NodePtr = ilist_node_access::getNext(NodePtr); + NodePtr = ilist_node_access::getNext(*NodePtr); return *this; } ilist_iterator operator--(int) { @@ -271,6 +260,64 @@ template<typename NodeTy> struct simplify_type<const ilist_iterator<NodeTy> > { } }; +/// Implementations of list algorithms using ilist_node_base. +class ilist_base { +public: + static void insertBeforeImpl(ilist_node_base &Next, ilist_node_base &N) { + ilist_node_base &Prev = *Next.getPrev(); + N.setNext(&Next); + N.setPrev(&Prev); + Prev.setNext(&N); + Next.setPrev(&N); + } + + static void removeImpl(ilist_node_base &N) { + ilist_node_base *Prev = N.getPrev(); + ilist_node_base *Next = N.getNext(); + Next->setPrev(Prev); + Prev->setNext(Next); + + // Not strictly necessary, but helps catch a class of bugs. + N.setPrev(nullptr); + N.setNext(nullptr); + } + + static void transferBeforeImpl(ilist_node_base &Next, ilist_node_base &First, + ilist_node_base &Last) { + assert(&Next != &Last && "Should be checked by callers"); + assert(&First != &Last && "Should be checked by callers"); + // Position cannot be contained in the range to be transferred. + assert(&Next != &First && + // Check for the most common mistake. + "Insertion point can't be one of the transferred nodes"); + + ilist_node_base &Final = *Last.getPrev(); + + // Detach from old list/position. + First.getPrev()->setNext(&Last); + Last.setPrev(First.getPrev()); + + // Splice [First, Final] into its new list/position. + ilist_node_base &Prev = *Next.getPrev(); + Final.setNext(&Next); + First.setPrev(&Prev); + Prev.setNext(&First); + Next.setPrev(&Final); + } + + template <class T> + static void insertBefore(ilist_node<T> &Next, ilist_node<T> &N) { + insertBeforeImpl(Next, N); + } + + template <class T> static void remove(ilist_node<T> &N) { removeImpl(N); } + + template <class T> + static void transferBefore(ilist_node<T> &Next, ilist_node<T> &First, + ilist_node<T> &Last) { + transferBeforeImpl(Next, First, Last); + } +}; //===----------------------------------------------------------------------===// // @@ -280,7 +327,7 @@ template<typename NodeTy> struct simplify_type<const ilist_iterator<NodeTy> > { /// ilist_sentinel, which holds pointers to the first and last nodes in the /// list. template <typename NodeTy, typename Traits = ilist_traits<NodeTy>> -class iplist : public Traits, ilist_node_access { +class iplist : public Traits, ilist_base, ilist_node_access { // TODO: Drop this assertion and the transitive type traits anytime after // v4.0 is branched (i.e,. keep them for one release to help out-of-tree code // update). @@ -356,13 +403,7 @@ public: } iterator insert(iterator where, NodeTy *New) { - node_type *NewN = this->getNodePtr(New); - node_type *Next = where.getNodePtr(); - node_type *Prev = this->getPrev(Next); - this->setNext(NewN, Next); - this->setPrev(NewN, Prev); - this->setNext(Prev, NewN); - this->setPrev(Next, NewN); + ilist_base::insertBefore(*where.getNodePtr(), *this->getNodePtr(New)); this->addNodeToList(New); // Notify traits that we added a node... return iterator(New); @@ -381,24 +422,9 @@ public: NodeTy *remove(iterator &IT) { assert(IT != end() && "Cannot remove end of list!"); - NodeTy *Node = &*IT; - node_type *Base = this->getNodePtr(Node); - node_type *Next = this->getNext(Base); - node_type *Prev = this->getPrev(Base); - - this->setNext(Prev, Next); - this->setPrev(Next, Prev); - IT = iterator(*Next); + NodeTy *Node = &*IT++; + ilist_base::remove(*this->getNodePtr(Node)); this->removeNodeFromList(Node); // Notify traits that we removed a node... - - // Set the next/prev pointers of the current node to null. This isn't - // strictly required, but this catches errors where a node is removed from - // an ilist (and potentially deleted) with iterators still pointing at it. - // After those iterators are incremented or decremented, they become - // default-constructed iterators, and will assert on increment, decrement, - // and dereference instead of "usually working". - this->setNext(Base, nullptr); - this->setPrev(Base, nullptr); return Node; } @@ -431,32 +457,11 @@ private: // [first, last) into position. // void transfer(iterator position, iplist &L2, iterator first, iterator last) { - assert(first != last && "Should be checked by callers"); - // Position cannot be contained in the range to be transferred. - assert(position != first && - // Check for the most common mistake. - "Insertion point can't be one of the transferred nodes"); - if (position == last) return; - // Get raw hooks to the first and final nodes being transferred. - node_type *First = first.getNodePtr(); - node_type *Final = (--last).getNodePtr(); - - // Detach from old list/position. - node_type *Prev = this->getPrev(First); - node_type *Next = this->getNext(Final); - this->setNext(Prev, Next); - this->setPrev(Next, Prev); - - // Splice [First, Final] into its new list/position. - Next = position.getNodePtr(); - Prev = this->getPrev(Next); - this->setNext(Final, Next); - this->setPrev(First, Prev); - this->setNext(Prev, First); - this->setPrev(Next, Final); + ilist_base::transferBefore(*position.getNodePtr(), *first.getNodePtr(), + *last.getNodePtr()); // Callback. Note that the nodes have moved from before-last to // before-position. diff --git a/llvm/include/llvm/ADT/ilist_node.h b/llvm/include/llvm/ADT/ilist_node.h index 756745bd6da..a817b4b4a18 100644 --- a/llvm/include/llvm/ADT/ilist_node.h +++ b/llvm/include/llvm/ADT/ilist_node.h @@ -23,18 +23,22 @@ template<typename NodeTy> struct ilist_traits; /// Base class for ilist nodes. -struct ilist_node_base { +class ilist_node_base { #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS PointerIntPair<ilist_node_base *, 1> PrevAndSentinel; +#else + ilist_node_base *Prev = nullptr; +#endif + ilist_node_base *Next = nullptr; +public: +#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); } ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); } bool isKnownSentinel() const { return PrevAndSentinel.getInt(); } void initializeSentinel() { PrevAndSentinel.setInt(true); } #else - ilist_node_base *Prev = nullptr; - void setPrev(ilist_node_base *Prev) { this->Prev = Prev; } ilist_node_base *getPrev() const { return Prev; } @@ -42,7 +46,8 @@ struct ilist_node_base { void initializeSentinel() {} #endif - ilist_node_base *Next = nullptr; + void setNext(ilist_node_base *Next) { this->Next = Next; } + ilist_node_base *getNext() const { return Next; } }; struct ilist_node_access; @@ -51,6 +56,7 @@ template <typename NodeTy> class ilist_sentinel; /// Templated wrapper class. template <typename NodeTy> class ilist_node : ilist_node_base { + friend class ilist_base; friend struct ilist_node_access; friend struct ilist_traits<NodeTy>; friend class ilist_iterator<NodeTy>; @@ -63,15 +69,19 @@ private: ilist_node *getPrev() { return static_cast<ilist_node *>(ilist_node_base::getPrev()); } - ilist_node *getNext() { return static_cast<ilist_node *>(Next); } + ilist_node *getNext() { + return static_cast<ilist_node *>(ilist_node_base::getNext()); + } const ilist_node *getPrev() const { return static_cast<ilist_node *>(ilist_node_base::getPrev()); } - const ilist_node *getNext() const { return static_cast<ilist_node *>(Next); } + const ilist_node *getNext() const { + return static_cast<ilist_node *>(ilist_node_base::getNext()); + } void setPrev(ilist_node *N) { ilist_node_base::setPrev(N); } - void setNext(ilist_node *N) { Next = N; } + void setNext(ilist_node *N) { ilist_node_base::setNext(N); } public: ilist_iterator<NodeTy> getIterator() { return ilist_iterator<NodeTy>(*this); } diff --git a/llvm/unittests/ADT/CMakeLists.txt b/llvm/unittests/ADT/CMakeLists.txt index 881d197a008..485c0e8690d 100644 --- a/llvm/unittests/ADT/CMakeLists.txt +++ b/llvm/unittests/ADT/CMakeLists.txt @@ -18,6 +18,9 @@ set(ADTSources FunctionRefTest.cpp HashingTest.cpp ilistTest.cpp + IListBaseTest.cpp + IListNodeBaseTest.cpp + IListSentinelTest.cpp ImmutableMapTest.cpp ImmutableSetTest.cpp IntEqClassesTest.cpp diff --git a/llvm/unittests/ADT/IListBaseTest.cpp b/llvm/unittests/ADT/IListBaseTest.cpp new file mode 100644 index 00000000000..1cb8fff5561 --- /dev/null +++ b/llvm/unittests/ADT/IListBaseTest.cpp @@ -0,0 +1,102 @@ +//===- unittests/ADT/IListBaseTest.cpp - ilist_base 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/ilist.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(IListBaseTest, insertBeforeImpl) { + ilist_node_base S, A, B; + // [S] <-> [S] + S.setPrev(&S); + S.setNext(&S); + + // [S] <-> A <-> [S] + ilist_base::insertBeforeImpl(S, A); + EXPECT_EQ(&A, S.getPrev()); + EXPECT_EQ(&S, A.getPrev()); + EXPECT_EQ(&A, S.getNext()); + EXPECT_EQ(&S, A.getNext()); + + // [S] <-> A <-> B <-> [S] + ilist_base::insertBeforeImpl(S, B); + EXPECT_EQ(&B, S.getPrev()); + EXPECT_EQ(&A, B.getPrev()); + EXPECT_EQ(&S, A.getPrev()); + EXPECT_EQ(&A, S.getNext()); + EXPECT_EQ(&B, A.getNext()); + EXPECT_EQ(&S, B.getNext()); +} + +TEST(IListBaseTest, removeImpl) { + ilist_node_base S, A, B; + + // [S] <-> A <-> B <-> [S] + S.setPrev(&S); + S.setNext(&S); + ilist_base::insertBeforeImpl(S, A); + ilist_base::insertBeforeImpl(S, B); + + // [S] <-> B <-> [S] + ilist_base::removeImpl(A); + EXPECT_EQ(&B, S.getPrev()); + EXPECT_EQ(&S, B.getPrev()); + EXPECT_EQ(&B, S.getNext()); + EXPECT_EQ(&S, B.getNext()); + EXPECT_EQ(nullptr, A.getPrev()); + EXPECT_EQ(nullptr, A.getNext()); + + // [S] <-> [S] + ilist_base::removeImpl(B); + EXPECT_EQ(&S, S.getPrev()); + EXPECT_EQ(&S, S.getNext()); + EXPECT_EQ(nullptr, B.getPrev()); + EXPECT_EQ(nullptr, B.getNext()); +} + +TEST(IListBaseTest, transferBeforeImpl) { + ilist_node_base S1, S2, A, B, C, D, E; + + // [S1] <-> A <-> B <-> C <-> [S1] + S1.setPrev(&S1); + S1.setNext(&S1); + ilist_base::insertBeforeImpl(S1, A); + ilist_base::insertBeforeImpl(S1, B); + ilist_base::insertBeforeImpl(S1, C); + + // [S2] <-> D <-> E <-> [S2] + S2.setPrev(&S2); + S2.setNext(&S2); + ilist_base::insertBeforeImpl(S2, D); + ilist_base::insertBeforeImpl(S2, E); + + // [S1] <-> C <-> [S1] + ilist_base::transferBeforeImpl(D, A, C); + EXPECT_EQ(&C, S1.getPrev()); + EXPECT_EQ(&S1, C.getPrev()); + EXPECT_EQ(&C, S1.getNext()); + EXPECT_EQ(&S1, C.getNext()); + + // [S2] <-> A <-> B <-> D <-> E <-> [S2] + EXPECT_EQ(&E, S2.getPrev()); + EXPECT_EQ(&D, E.getPrev()); + EXPECT_EQ(&B, D.getPrev()); + EXPECT_EQ(&A, B.getPrev()); + EXPECT_EQ(&S2, A.getPrev()); + EXPECT_EQ(&A, S2.getNext()); + EXPECT_EQ(&B, A.getNext()); + EXPECT_EQ(&D, B.getNext()); + EXPECT_EQ(&E, D.getNext()); + EXPECT_EQ(&S2, E.getNext()); +} + +} // end namespace diff --git a/llvm/unittests/ADT/IListNodeBaseTest.cpp b/llvm/unittests/ADT/IListNodeBaseTest.cpp new file mode 100644 index 00000000000..1e9c2a1fa04 --- /dev/null +++ b/llvm/unittests/ADT/IListNodeBaseTest.cpp @@ -0,0 +1,60 @@ +//===- unittests/ADT/IListNodeBaseTest.cpp - ilist_node_base 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/ilist_node.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(IListNodeBaseTest, DefaultConstructor) { + ilist_node_base A; + EXPECT_EQ(nullptr, A.getPrev()); + EXPECT_EQ(nullptr, A.getNext()); + EXPECT_FALSE(A.isKnownSentinel()); +} + +TEST(IListNodeBaseTest, setPrevAndNext) { + ilist_node_base A, B, C; + A.setPrev(&B); + EXPECT_EQ(&B, A.getPrev()); + EXPECT_EQ(nullptr, A.getNext()); + EXPECT_EQ(nullptr, B.getPrev()); + EXPECT_EQ(nullptr, B.getNext()); + EXPECT_EQ(nullptr, C.getPrev()); + EXPECT_EQ(nullptr, C.getNext()); + + A.setNext(&C); + EXPECT_EQ(&B, A.getPrev()); + EXPECT_EQ(&C, A.getNext()); + EXPECT_EQ(nullptr, B.getPrev()); + EXPECT_EQ(nullptr, B.getNext()); + EXPECT_EQ(nullptr, C.getPrev()); + EXPECT_EQ(nullptr, C.getNext()); +} + +TEST(IListNodeBaseTest, isKnownSentinel) { + ilist_node_base A, B; + EXPECT_FALSE(A.isKnownSentinel()); + A.setPrev(&B); + A.setNext(&B); + EXPECT_EQ(&B, A.getPrev()); + EXPECT_EQ(&B, A.getNext()); + A.initializeSentinel(); +#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS + EXPECT_TRUE(A.isKnownSentinel()); +#else + EXPECT_FALSE(A.isKnownSentinel()); +#endif + EXPECT_EQ(&B, A.getPrev()); + EXPECT_EQ(&B, A.getNext()); +} + +} // end namespace diff --git a/llvm/unittests/ADT/IListSentinelTest.cpp b/llvm/unittests/ADT/IListSentinelTest.cpp new file mode 100644 index 00000000000..533421e8504 --- /dev/null +++ b/llvm/unittests/ADT/IListSentinelTest.cpp @@ -0,0 +1,37 @@ +//===- unittests/ADT/IListSentinelTest.cpp - ilist_sentinel 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/ilist.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class Node : public ilist_node<Node> {}; + +TEST(IListSentinelTest, DefaultConstructor) { + ilist_sentinel<Node> S; + EXPECT_EQ(&S, ilist_node_access::getPrev(S)); + EXPECT_EQ(&S, ilist_node_access::getNext(S)); +#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS + EXPECT_TRUE(S.isKnownSentinel()); +#else + EXPECT_FALSE(S.isKnownSentinel()); +#endif +} + +TEST(IListSentinelTest, NormalNodeIsNotKnownSentinel) { + Node N; + EXPECT_EQ(nullptr, ilist_node_access::getPrev(N)); + EXPECT_EQ(nullptr, ilist_node_access::getNext(N)); + EXPECT_FALSE(N.isKnownSentinel()); +} + +} // end namespace |