diff options
| author | Kristof Umann <dkszelethus@gmail.com> | 2018-08-28 14:17:51 +0000 |
|---|---|---|
| committer | Kristof Umann <dkszelethus@gmail.com> | 2018-08-28 14:17:51 +0000 |
| commit | d0202395f17408b554384034b6476c6272bf1be3 (patch) | |
| tree | 0ba600b29520927a99ab844d8407fffef719a9e5 | |
| parent | fa8ce34534886bb47eb82e2c4ad372c16a0787b9 (diff) | |
| download | bcm5719-llvm-d0202395f17408b554384034b6476c6272bf1be3.tar.gz bcm5719-llvm-d0202395f17408b554384034b6476c6272bf1be3.zip | |
[ADT] ImmutableList no longer requires elements to be copy constructible
ImmutableList used to require elements to have a copy constructor for no
good reason, this patch aims to fix this.
It also required but did not enforce its elements to be trivially
destructible, so a new static_assert is added to guard against misuse.
Differential Revision: https://reviews.llvm.org/D49985
llvm-svn: 340824
| -rw-r--r-- | llvm/include/llvm/ADT/ImmutableList.h | 29 | ||||
| -rw-r--r-- | llvm/unittests/ADT/ImmutableListTest.cpp | 43 |
2 files changed, 64 insertions, 8 deletions
diff --git a/llvm/include/llvm/ADT/ImmutableList.h b/llvm/include/llvm/ADT/ImmutableList.h index deafa271b38..4bd56207281 100644 --- a/llvm/include/llvm/ADT/ImmutableList.h +++ b/llvm/include/llvm/ADT/ImmutableList.h @@ -31,8 +31,9 @@ class ImmutableListImpl : public FoldingSetNode { T Head; const ImmutableListImpl* Tail; - ImmutableListImpl(const T& head, const ImmutableListImpl* tail = nullptr) - : Head(head), Tail(tail) {} + template <typename ElemT> + ImmutableListImpl(ElemT &&head, const ImmutableListImpl *tail = nullptr) + : Head(std::forward<ElemT>(head)), Tail(tail) {} public: ImmutableListImpl(const ImmutableListImpl &) = delete; @@ -66,6 +67,9 @@ public: using value_type = T; using Factory = ImmutableListFactory<T>; + static_assert(std::is_trivially_destructible<T>::value, + "T must be trivially destructible!"); + private: const ImmutableListImpl<T>* X; @@ -166,7 +170,8 @@ public: if (ownsAllocator()) delete &getAllocator(); } - LLVM_NODISCARD ImmutableList<T> concat(const T &Head, ImmutableList<T> Tail) { + template <typename ElemT> + LLVM_NODISCARD ImmutableList<T> concat(ElemT &&Head, ImmutableList<T> Tail) { // Profile the new list to see if it already exists in our cache. FoldingSetNodeID ID; void* InsertPos; @@ -179,7 +184,7 @@ public: // The list does not exist in our cache. Create it. BumpPtrAllocator& A = getAllocator(); L = (ListTy*) A.Allocate<ListTy>(); - new (L) ListTy(Head, TailImpl); + new (L) ListTy(std::forward<ElemT>(Head), TailImpl); // Insert the new list into the cache. Cache.InsertNode(L, InsertPos); @@ -188,16 +193,24 @@ public: return L; } - LLVM_NODISCARD ImmutableList<T> add(const T& D, ImmutableList<T> L) { - return concat(D, L); + template <typename ElemT> + LLVM_NODISCARD ImmutableList<T> add(ElemT &&Data, ImmutableList<T> L) { + return concat(std::forward<ElemT>(Data), L); + } + + template <typename ...CtorArgs> + LLVM_NODISCARD ImmutableList<T> emplace(ImmutableList<T> Tail, + CtorArgs &&...Args) { + return concat(T(std::forward<CtorArgs>(Args)...), Tail); } ImmutableList<T> getEmptyList() const { return ImmutableList<T>(nullptr); } - ImmutableList<T> create(const T& X) { - return concat(X, getEmptyList()); + template <typename ElemT> + ImmutableList<T> create(ElemT &&Data) { + return concat(std::forward<ElemT>(Data), getEmptyList()); } }; diff --git a/llvm/unittests/ADT/ImmutableListTest.cpp b/llvm/unittests/ADT/ImmutableListTest.cpp index 0e72769ed10..df150cb1519 100644 --- a/llvm/unittests/ADT/ImmutableListTest.cpp +++ b/llvm/unittests/ADT/ImmutableListTest.cpp @@ -150,6 +150,49 @@ TEST_F(ImmutableListTest, MultiElemIntListTest) { EXPECT_TRUE(L5.isEqual(L5)); } +template <typename Fundamental> +struct ExplicitCtorWrapper : public Wrapper<Fundamental> { + explicit ExplicitCtorWrapper(Fundamental F) : Wrapper<Fundamental>(F) {} + ExplicitCtorWrapper(const ExplicitCtorWrapper &) = delete; + ExplicitCtorWrapper(ExplicitCtorWrapper &&) = default; + ExplicitCtorWrapper &operator=(const ExplicitCtorWrapper &) = delete; + ExplicitCtorWrapper &operator=(ExplicitCtorWrapper &&) = default; +}; + +TEST_F(ImmutableListTest, EmplaceIntListTest) { + ImmutableList<ExplicitCtorWrapper<int>>::Factory f; + + ImmutableList<ExplicitCtorWrapper<int>> L = f.getEmptyList(); + ImmutableList<ExplicitCtorWrapper<int>> L2 = f.emplace(L, 3); + + ImmutableList<ExplicitCtorWrapper<int>> L3 = + f.add(ExplicitCtorWrapper<int>(2), L2); + + ImmutableList<ExplicitCtorWrapper<int>> L4 = + f.emplace(L3, ExplicitCtorWrapper<int>(1)); + + ImmutableList<ExplicitCtorWrapper<int>> L5 = + f.add(ExplicitCtorWrapper<int>(1), L3); + + 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<Wrapper<char>>::Factory f; ImmutableList<Wrapper<char>> L = f.getEmptyList(); |

