llvm.org GIT mirror llvm / cd6f391
Add llvm::Any. This is analogous to std::any which is only available in C++17. Differential Revision: https://reviews.llvm.org/D48807 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@337573 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 2 years ago
4 changed file(s) with 333 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 //===- Any.h - Generic type erased holder of any type -----------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file provides Any, a non-template class modeled in the spirit of
10 // std::any. The idea is to provide a type-safe replacement for C's void*.
11 // It can hold a value of any copy-constructible copy-assignable type
12 //
13 //===----------------------------------------------------------------------===//
14
15 #ifndef LLVM_ADT_ANY_H
16 #define LLVM_ADT_ANY_H
17
18 #include "llvm/ADT/STLExtras.h"
19
20 #include
21 #include
22 #include
23
24 namespace llvm {
25
26 class Any {
27 template struct TypeId { static const char Id = 0; };
28
29 struct StorageBase {
30 virtual ~StorageBase() = default;
31 virtual std::unique_ptr clone() const = 0;
32 virtual const void *id() const = 0;
33 };
34
35 template struct StorageImpl : public StorageBase {
36 explicit StorageImpl(const T &Value) : Value(Value) {}
37
38 explicit StorageImpl(T &&Value) : Value(std::move(Value)) {}
39
40 std::unique_ptr clone() const override {
41 return llvm::make_unique>(Value);
42 }
43
44 const void *id() const override { return &TypeId::Id; }
45
46 T Value;
47
48 private:
49 StorageImpl &operator=(const StorageImpl &Other) = delete;
50 StorageImpl(const StorageImpl &Other) = delete;
51 };
52
53 public:
54 Any() = default;
55
56 Any(const Any &Other)
57 : Storage(Other.Storage ? Other.Storage->clone() : nullptr) {}
58
59 // When T is Any or T is not copy-constructible we need to explicitly disable
60 // the forwarding constructor so that the copy constructor gets selected
61 // instead.
62 template <
63 typename T,
64 typename std::enable_if<
65 llvm::conjunction<
66 llvm::negation::type, Any>>,
67 std::is_copy_constructible::type>>::value,
68 int>::type = 0>
69 Any(T &&Value) {
70 using U = typename std::decay::type;
71 Storage = llvm::make_unique>(std::forward(Value));
72 }
73
74 Any(Any &&Other) : Storage(std::move(Other.Storage)) {}
75
76 Any &swap(Any &Other) {
77 std::swap(Storage, Other.Storage);
78 return *this;
79 }
80
81 Any &operator=(Any Other) {
82 Storage = std::move(Other.Storage);
83 return *this;
84 }
85
86 bool hasValue() const { return !!Storage; }
87
88 void reset() { Storage.reset(); }
89
90 private:
91 template friend T any_cast(const Any &Value);
92 template friend T any_cast(Any &Value);
93 template friend T any_cast(Any &&Value);
94 template friend const T *any_cast(const Any *Value);
95 template friend T *any_cast(Any *Value);
96 template friend bool any_isa(const Any &Value);
97
98 std::unique_ptr Storage;
99 };
100
101 template bool any_isa(const Any &Value) {
102 if (!Value.Storage)
103 return false;
104 using U =
105 typename std::remove_cv::type>::type;
106 return Value.Storage->id() == &Any::TypeId::Id;
107 }
108
109 template T any_cast(const Any &Value) {
110 using U =
111 typename std::remove_cv::type>::type;
112 return static_cast(*any_cast(&operand));
113 }
114
115 template T any_cast(Any &Value) {
116 using U =
117 typename std::remove_cv::type>::type;
118 return static_cast(*any_cast(&Value));
119 }
120
121 template T any_cast(Any &&Value) {
122 using U =
123 typename std::remove_cv::type>::type;
124 return static_cast(std::move(*any_cast(&Value)));
125 }
126
127 template const T *any_cast(const Any *Value) {
128 using U =
129 typename std::remove_cv::type>::type;
130 assert(Value && any_isa(*Value) && "Bad any cast!");
131 if (!Value || !any_isa(*Value))
132 return nullptr;
133 return &static_cast &>(*Value->Storage).Value;
134 }
135
136 template T *any_cast(Any *Value) {
137 using U = typename std::decay::type;
138 assert(Value && any_isa(*Value) && "Bad any cast!");
139 if (!Value || !any_isa(*Value))
140 return nullptr;
141 return &static_cast &>(*Value->Storage).Value;
142 }
143
144 } // end namespace llvm
145
146 #endif // LLVM_ADT_ANY_H
5757 } // end namespace detail
5858
5959 //===----------------------------------------------------------------------===//
60 // Extra additions to
61 //===----------------------------------------------------------------------===//
62
63 template struct negation : std::bool_constant {};
64
65 template struct conjunction : std::true_type {};
66 template struct conjunction : B1 {};
67 template
68 struct conjunction
69 : std::conditional, B1>::type {};
70
71 //===----------------------------------------------------------------------===//
6072 // Extra additions to
6173 //===----------------------------------------------------------------------===//
6274
0 //===- llvm/unittest/Support/AnyTest.cpp - Any tests ---===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ADT/Any.h"
10 #include "gtest/gtest.h"
11 #include
12
13 using namespace llvm;
14
15 namespace {
16
17 // Make sure we can construct, copy-construct, move-construct, and assign Any's.
18 TEST(AnyTest, ConstructionAndAssignment) {
19 llvm::Any A;
20 llvm::Any B{7};
21 llvm::Any C{8};
22 llvm::Any D{"hello"};
23 llvm::Any E{3.7};
24
25 // An empty Any is not anything.
26 EXPECT_FALSE(A.hasValue());
27 EXPECT_FALSE(any_isa(A));
28
29 // An int is an int but not something else.
30 EXPECT_TRUE(B.hasValue());
31 EXPECT_TRUE(any_isa(B));
32 EXPECT_FALSE(any_isa(B));
33
34 EXPECT_TRUE(C.hasValue());
35 EXPECT_TRUE(any_isa(C));
36
37 // A const char * is a const char * but not an int.
38 EXPECT_TRUE(D.hasValue());
39 EXPECT_TRUE(any_isa(D));
40 EXPECT_FALSE(any_isa(D));
41
42 // A double is a double but not a float.
43 EXPECT_TRUE(E.hasValue());
44 EXPECT_TRUE(any_isa(E));
45 EXPECT_FALSE(any_isa(E));
46
47 // After copy constructing from an int, the new item and old item are both
48 // ints.
49 llvm::Any F(B);
50 EXPECT_TRUE(B.hasValue());
51 EXPECT_TRUE(F.hasValue());
52 EXPECT_TRUE(any_isa(F));
53 EXPECT_TRUE(any_isa(B));
54
55 // After move constructing from an int, the new item is an int and the old one
56 // isn't.
57 llvm::Any G(std::move(C));
58 EXPECT_FALSE(C.hasValue());
59 EXPECT_TRUE(G.hasValue());
60 EXPECT_TRUE(any_isa(G));
61 EXPECT_FALSE(any_isa(C));
62
63 // After copy-assigning from an int, the new item and old item are both ints.
64 A = F;
65 EXPECT_TRUE(A.hasValue());
66 EXPECT_TRUE(F.hasValue());
67 EXPECT_TRUE(any_isa(A));
68 EXPECT_TRUE(any_isa(F));
69
70 // After move-assigning from an int, the new item and old item are both ints.
71 B = std::move(G);
72 EXPECT_TRUE(B.hasValue());
73 EXPECT_FALSE(G.hasValue());
74 EXPECT_TRUE(any_isa(B));
75 EXPECT_FALSE(any_isa(G));
76 }
77
78 TEST(AnyTest, GoodAnyCast) {
79 llvm::Any A;
80 llvm::Any B{7};
81 llvm::Any C{8};
82 llvm::Any D{"hello"};
83 llvm::Any E{'x'};
84
85 // Check each value twice to make sure it isn't damaged by the cast.
86 EXPECT_EQ(7, llvm::any_cast(B));
87 EXPECT_EQ(7, llvm::any_cast(B));
88
89 EXPECT_STREQ("hello", llvm::any_cast(D));
90 EXPECT_STREQ("hello", llvm::any_cast(D));
91
92 EXPECT_EQ('x', llvm::any_cast(E));
93 EXPECT_EQ('x', llvm::any_cast(E));
94
95 llvm::Any F(B);
96 EXPECT_EQ(7, llvm::any_cast(F));
97 EXPECT_EQ(7, llvm::any_cast(F));
98
99 llvm::Any G(std::move(C));
100 EXPECT_EQ(8, llvm::any_cast(G));
101 EXPECT_EQ(8, llvm::any_cast(G));
102
103 A = F;
104 EXPECT_EQ(7, llvm::any_cast(A));
105 EXPECT_EQ(7, llvm::any_cast(A));
106
107 E = std::move(G);
108 EXPECT_EQ(8, llvm::any_cast(E));
109 EXPECT_EQ(8, llvm::any_cast(E));
110
111 // Make sure we can any_cast from an rvalue and that it's properly destroyed
112 // in the process.
113 EXPECT_EQ(8, llvm::any_cast(std::move(E)));
114 EXPECT_TRUE(E.hasValue());
115
116 // Make sure moving from pointers gives back pointers, and that we can modify
117 // the underlying value through those pointers.
118 EXPECT_EQ(7, *llvm::any_cast(&A));
119 int *N = llvm::any_cast(&A);
120 *N = 42;
121 EXPECT_EQ(42, llvm::any_cast(A));
122
123 // Make sure that we can any_cast to a reference and this is considered a good
124 // cast, resulting in an lvalue which can be modified.
125 llvm::any_cast(A) = 43;
126 EXPECT_EQ(43, llvm::any_cast(A));
127 }
128
129 TEST(AnyTest, CopiesAndMoves) {
130 struct TestType {
131 TestType() = default;
132 TestType(const TestType &Other)
133 : Copies(Other.Copies + 1), Moves(Other.Moves) {}
134 TestType(TestType &&Other) : Copies(Other.Copies), Moves(Other.Moves + 1) {}
135 int Copies = 0;
136 int Moves = 0;
137 };
138
139 // One move to get TestType into the Any, and one move on the cast.
140 TestType T1 = llvm::any_cast(Any{TestType()});
141 EXPECT_EQ(0, T1.Copies);
142 EXPECT_EQ(2, T1.Moves);
143
144 // One move to get TestType into the Any, and one copy on the cast.
145 Any A{TestType()};
146 TestType T2 = llvm::any_cast(A);
147 EXPECT_EQ(1, T2.Copies);
148 EXPECT_EQ(1, T2.Moves);
149
150 // One move to get TestType into the Any, and one move on the cast.
151 TestType T3 = llvm::any_cast(std::move(A));
152 EXPECT_EQ(0, T3.Copies);
153 EXPECT_EQ(2, T3.Moves);
154 }
155
156 TEST(AnyTest, BadAnyCast) {
157 llvm::Any A;
158 llvm::Any B{7};
159 llvm::Any C{"hello"};
160 llvm::Any D{'x'};
161
162 EXPECT_DEBUG_DEATH(llvm::any_cast(A), "");
163
164 EXPECT_DEBUG_DEATH(llvm::any_cast(B), "");
165 EXPECT_DEBUG_DEATH(llvm::any_cast(B), "");
166
167 EXPECT_DEBUG_DEATH(llvm::any_cast(C), "");
168
169 EXPECT_DEBUG_DEATH(llvm::any_cast(D), "");
170 }
171
172 } // anonymous namespace
22 )
33
44 add_llvm_unittest(ADTTests
5 AnyTest.cpp
56 APFloatTest.cpp
67 APIntTest.cpp
78 APSIntTest.cpp