Index: include/llvm/ADT/ImmutableList.h =================================================================== --- include/llvm/ADT/ImmutableList.h +++ include/llvm/ADT/ImmutableList.h @@ -31,8 +31,8 @@ T Head; const ImmutableListImpl* Tail; - ImmutableListImpl(const T& head, const ImmutableListImpl* tail = nullptr) - : Head(head), Tail(tail) {} + ImmutableListImpl(T &&head, const ImmutableListImpl *tail = nullptr) + : Head(std::move(head)), Tail(tail) {} public: ImmutableListImpl(const ImmutableListImpl &) = delete; @@ -166,7 +166,7 @@ if (ownsAllocator()) delete &getAllocator(); } - LLVM_NODISCARD ImmutableList concat(const T &Head, ImmutableList Tail) { + LLVM_NODISCARD ImmutableList concat(ImmutableList Tail, T Head) { // Profile the new list to see if it already exists in our cache. FoldingSetNodeID ID; void* InsertPos; @@ -179,7 +179,7 @@ // The list does not exist in our cache. Create it. BumpPtrAllocator& A = getAllocator(); L = (ListTy*) A.Allocate(); - new (L) ListTy(Head, TailImpl); + new (L) ListTy(std::move(Head), TailImpl); // Insert the new list into the cache. Cache.InsertNode(L, InsertPos); @@ -188,16 +188,21 @@ return L; } - LLVM_NODISCARD ImmutableList add(const T& D, ImmutableList L) { - return concat(D, L); + LLVM_NODISCARD ImmutableList add(ImmutableList L, T Data) { + return concat(L, std::move(Data)); + } + + template + LLVM_NODISCARD ImmutableList emplace(ImmutableList Tail, CtorArgs &&...Args) { + return concat(Tail, T(std::forward(Args)...)); } ImmutableList getEmptyList() const { return ImmutableList(nullptr); } - ImmutableList create(const T& X) { - return Concat(X, getEmptyList()); + ImmutableList create(T Data) { + return concat(getEmptyList(), std::move(Data)); } }; Index: unittests/ADT/CMakeLists.txt =================================================================== --- unittests/ADT/CMakeLists.txt +++ unittests/ADT/CMakeLists.txt @@ -26,6 +26,7 @@ IListNodeTest.cpp IListSentinelTest.cpp IListTest.cpp + ImmutableListTest.cpp ImmutableMapTest.cpp ImmutableSetTest.cpp IntEqClassesTest.cpp Index: unittests/ADT/ImmutableListTest.cpp =================================================================== --- /dev/null +++ unittests/ADT/ImmutableListTest.cpp @@ -0,0 +1,241 @@ +//===--------- ImmutableListTest.cpp - ImmutableList unit tests --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. Lee LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/ImmutableList.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +template struct Wrapper : llvm::FoldingSetNode { + Fundamental F; + + Wrapper(Fundamental F) : F(F) {} + + operator Fundamental() const { return F; } + + void Profile(FoldingSetNodeID &ID) const { ID.AddInteger(F); } +}; + +class ImmutableListTest : public testing::Test {}; + +void concat(const ImmutableList> &L, char *Buffer) { + int Index = 0; + for (ImmutableList>::iterator It = L.begin(), End = L.end(); + It != End; ++It) { + Buffer[Index++] = *It; + } + Buffer[Index] = '\0'; +} + +TEST_F(ImmutableListTest, EmptyIntListTest) { + ImmutableList>::Factory f; + + EXPECT_TRUE(f.getEmptyList() == f.getEmptyList()); + EXPECT_TRUE(f.getEmptyList().isEqual(f.getEmptyList())); + EXPECT_TRUE(f.getEmptyList().isEmpty()); + + ImmutableList> L = f.getEmptyList(); + EXPECT_EQ(nullptr, L.getTail().getInternalPointer()); + EXPECT_TRUE(L.getTail().isEmpty()); + EXPECT_TRUE(L.begin() == L.end()); +} + +TEST_F(ImmutableListTest, OneElemIntListTest) { + ImmutableList>::Factory f; + ImmutableList> L = f.getEmptyList(); + + ImmutableList> L2 = f.add(L, 3); + EXPECT_TRUE(L.isEmpty()); + EXPECT_FALSE(L2.isEmpty()); + EXPECT_TRUE(L2.getTail().isEmpty()); + + EXPECT_FALSE(L == L2); + EXPECT_TRUE(L == L2.getTail()); + EXPECT_FALSE(L.isEqual(L2)); + EXPECT_TRUE(L.isEqual(L2.getTail())); + EXPECT_FALSE(L2.begin() == L2.end()); + EXPECT_TRUE(L2.begin() != L2.end()); + + EXPECT_FALSE(L.contains(3)); + EXPECT_EQ(3, L2.getHead()); + EXPECT_TRUE(L2.contains(3)); + + ImmutableList> L3 = f.add(L, 2); + EXPECT_TRUE(L.isEmpty()); + EXPECT_FALSE(L3.isEmpty()); + EXPECT_FALSE(L == L3); + EXPECT_FALSE(L.contains(2)); + EXPECT_TRUE(L3.contains(2)); + EXPECT_EQ(2, L3.getHead()); + + EXPECT_FALSE(L2 == L3); + EXPECT_FALSE(L2.contains(2)); +} + +TEST_F(ImmutableListTest, CreatingIntListTest) { + ImmutableList>::Factory f; + + ImmutableList> L = f.getEmptyList(); + ImmutableList> L2 = f.create(3); + + EXPECT_FALSE(L2.isEmpty()); + EXPECT_TRUE(L2.getTail().isEmpty()); + EXPECT_EQ(3, L2.getHead()); + EXPECT_TRUE(L.isEqual(L2.getTail())); + EXPECT_TRUE(L2.getTail().isEqual(L)); +} + +TEST_F(ImmutableListTest, MultiElemIntListTest) { + ImmutableList>::Factory f; + + ImmutableList> L = f.getEmptyList(); + ImmutableList> L2 = f.add(f.add(f.add(L, 3), 4), 5); + ImmutableList> L3 = f.add(f.add(f.add(L2, 9), 20), 43); + ImmutableList> L4 = f.add(L2, 9); + ImmutableList> L5 = f.add(L2, 9); + + EXPECT_TRUE(L.isEmpty()); + EXPECT_FALSE(L2.isEmpty()); + EXPECT_FALSE(L3.isEmpty()); + EXPECT_FALSE(L4.isEmpty()); + + EXPECT_FALSE(L.contains(3)); + EXPECT_FALSE(L.contains(9)); + + EXPECT_TRUE(L2.contains(3)); + EXPECT_TRUE(L2.contains(4)); + EXPECT_TRUE(L2.contains(5)); + EXPECT_FALSE(L2.contains(9)); + EXPECT_FALSE(L2.contains(0)); + + EXPECT_EQ(5, L2.getHead()); + EXPECT_EQ(4, L2.getTail().getHead()); + EXPECT_EQ(3, L2.getTail().getTail().getHead()); + + EXPECT_TRUE(L3.contains(43)); + EXPECT_TRUE(L3.contains(20)); + EXPECT_TRUE(L3.contains(9)); + EXPECT_TRUE(L3.contains(3)); + EXPECT_TRUE(L3.contains(4)); + EXPECT_TRUE(L3.contains(5)); + EXPECT_FALSE(L3.contains(0)); + + EXPECT_EQ(43, L3.getHead()); + EXPECT_EQ(20, L3.getTail().getHead()); + EXPECT_EQ(9, L3.getTail().getTail().getHead()); + + EXPECT_TRUE(L3.getTail().getTail().getTail() == L2); + EXPECT_TRUE(L2 == L3.getTail().getTail().getTail()); + EXPECT_TRUE(L3.getTail().getTail().getTail().isEqual(L2)); + EXPECT_TRUE(L2.isEqual(L3.getTail().getTail().getTail())); + + EXPECT_TRUE(L4.contains(9)); + EXPECT_TRUE(L4.contains(3)); + EXPECT_TRUE(L4.contains(4)); + EXPECT_TRUE(L4.contains(5)); + EXPECT_FALSE(L4.contains(20)); + EXPECT_FALSE(L4.contains(43)); + EXPECT_TRUE(L4.isEqual(L4)); + EXPECT_TRUE(L4.isEqual(L5)); + + EXPECT_TRUE(L5.isEqual(L4)); + EXPECT_TRUE(L5.isEqual(L5)); +} + +template +struct ExplicitCtorWrapper : public Wrapper { + explicit ExplicitCtorWrapper(Fundamental F) : Wrapper(F) {} + ExplicitCtorWrapper(const ExplicitCtorWrapper &) = delete; + ExplicitCtorWrapper(ExplicitCtorWrapper &&) = default; + ExplicitCtorWrapper &operator=(const ExplicitCtorWrapper &) = delete; + ExplicitCtorWrapper &operator=(ExplicitCtorWrapper &&) = default; +}; + +TEST_F(ImmutableListTest, EmplaceIntListTest) { + ImmutableList>::Factory f; + + ImmutableList> L = f.getEmptyList(); + ImmutableList> L2 = f.emplace(L, 3); + + ImmutableList> L3 = + f.add(L2, ExplicitCtorWrapper(2)); + + ImmutableList> L4 = + f.emplace(L3, ExplicitCtorWrapper(1)); + + ImmutableList> L5 = + f.add(L3, ExplicitCtorWrapper(1)); + + EXPECT_FALSE(L2.isEmpty()); + EXPECT_TRUE(L2.getTail().isEmpty()); + EXPECT_EQ(3, L2.getHead()); + EXPECT_TRUE(L.isEqual(L2.getTail())); + EXPECT_TRUE(L2.getTail().isEqual(L)); + + EXPECT_FALSE(L3.isEmpty()); + EXPECT_FALSE(L2 == L3); + EXPECT_EQ(2, L3.getHead()); + EXPECT_TRUE(L2 == L3.getTail()); + + EXPECT_FALSE(L4.isEmpty()); + EXPECT_EQ(1, L4.getHead()); + EXPECT_TRUE(L3 == L4.getTail()); + + EXPECT_TRUE(L4 == L5); + EXPECT_TRUE(L3 == L5.getTail()); +} + +TEST_F(ImmutableListTest, CharListOrderingTest) { + ImmutableList>::Factory f; + ImmutableList> L = f.getEmptyList(); + + ImmutableList> L2 = f.add(f.add(f.add(L, 'a'), 'e'), 'i'); + ImmutableList> L3 = f.add(f.add(L2, 'o'), 'u'); + + char Buffer[10]; + concat(L3, Buffer); + + ASSERT_STREQ("uoiea", Buffer); +} + +TEST_F(ImmutableListTest, LongListOrderingTest) { + ImmutableList>::Factory f; + ImmutableList> L = f.getEmptyList(); + + ImmutableList> L2 = f.add(f.add(f.add(L, 5), 4), 3); + ImmutableList> L3 = f.add(f.add(f.add(L2, 2), 1), 0); + + int i = 0; + for (ImmutableList>::iterator I = L.begin(), E = L.end(); + I != E; ++I) { + ASSERT_EQ(i, *I); + i++; + } + ASSERT_EQ(0, i); + + i = 3; + for (ImmutableList>::iterator I = L2.begin(), E = L2.end(); + I != E; ++I) { + ASSERT_EQ(i, *I); + i++; + } + ASSERT_EQ(6, i); + + i = 0; + for (ImmutableList>::iterator I = L3.begin(), E = L3.end(); + I != E; ++I) { + ASSERT_EQ(i, *I); + i++; + } + ASSERT_EQ(6, i); +} + +} // namespace