-
Notifications
You must be signed in to change notification settings - Fork 36
/
test_any.cpp
317 lines (278 loc) · 8.42 KB
/
test_any.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
// Very simplist test, could be better.
#include "any.hpp"
#include "test_shared_lib.hpp"
#include <memory>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <vector>
#if defined(ANY_IMPL_NO_EXCEPTIONS) && defined(_MSC_VER)
# include <excpt.h>
#endif
#define CHECK(x) ((x)? (void)(0) : (void(fprintf(stdout, "Failed at %d:%s: %s\n", __LINE__, __FILE__, #x)), std::exit(EXIT_FAILURE)))
template<size_t N>
struct words
{
void* w[N];
};
struct big_type
{
char i_wanna_be_big[256];
std::string value;
big_type() :
value(std::string(300, 'b'))
{
i_wanna_be_big[0] = i_wanna_be_big[50] = 'k';
}
bool check()
{
CHECK(value.size() == 300);
CHECK(value.front() == 'b' && value.back() == 'b');
CHECK(i_wanna_be_big[0] == 'k' && i_wanna_be_big[50] == 'k');
return true;
}
};
// small type which has nothrow move ctor but throw copy ctor
struct regression1_type
{
const void* confuse_stack_storage = (void*)(0);
regression1_type() {}
regression1_type(const regression1_type&) {}
regression1_type(regression1_type&&) noexcept {}
regression1_type& operator=(const regression1_type&) { return *this; }
regression1_type& operator=(regression1_type&&) { return *this; }
};
int main()
{
using linb::any;
using linb::any_cast;
using linb::bad_any_cast;
using linb::make_any;
{
any x = 4;
any y = big_type();
any z = 6;
CHECK(any().empty());
CHECK(!any(1).empty());
CHECK(!any(big_type()).empty());
CHECK(!x.empty() && !y.empty() && !z.empty());
y.clear();
CHECK(!x.empty() && y.empty() && !z.empty());
x = y;
CHECK(x.empty() && y.empty() && !z.empty());
z = any();
CHECK(x.empty() && y.empty() && z.empty());
}
{
any o1 = make_any<std::vector<int>>({2, 2});
any o2 = make_any<std::vector<int>>(2, 2);
CHECK(any_cast<std::vector<int>>(o1) == any_cast<std::vector<int>>(o2));
}
#ifndef ANY_IMPL_NO_RTTI
{
CHECK(any().type() == typeid(void));
CHECK(any(4).type() == typeid(int));
CHECK(any(big_type()).type() == typeid(big_type));
CHECK(any(1.5f).type() == typeid(float));
}
#endif
{
bool except0 = false;
bool except1 = false, except2 = false;
bool except3 = false, except4 = false;
#ifndef ANY_IMPL_NO_EXCEPTIONS
try {
any_cast<int>(any());
}
catch(const bad_any_cast&) {
except0 = true;
}
try {
any_cast<int>(any(4.0f));
}
catch(const bad_any_cast&) {
except1 = true;
}
try {
any_cast<float>(any(4.0f));
}
catch(const bad_any_cast&) {
except2 = true;
}
try {
any_cast<float>(any(big_type()));
}
catch(const bad_any_cast&) {
except3 = true;
}
try {
any_cast<big_type>(any(big_type()));
}
catch(const bad_any_cast&) {
except4 = true;
}
#elif _MSC_VER
// we can test segmentation faults with msvc
# ifdef _CPPUNWIND
# error Must use msvc compiler with exceptions disabled (no /EHa, /EHsc, /EHs)
# endif
__try {
any_cast<int>(any());
} __except (EXCEPTION_EXECUTE_HANDLER) {
except0 = true;
}
__try {
any_cast<int>(any(4.0f));
} __except (EXCEPTION_EXECUTE_HANDLER) {
except1 = true;
}
__try {
any_cast<float>(any(4.0f));
} __except (EXCEPTION_EXECUTE_HANDLER) {
except2 = true;
}
__try {
any_cast<float>(any(big_type()));
} __except (EXCEPTION_EXECUTE_HANDLER) {
except3 = true;
}
__try {
any_cast<big_type>(any(big_type()));
} __except (EXCEPTION_EXECUTE_HANDLER) {
except4 = true;
}
#endif
CHECK(except0 == true);
CHECK(except1 == true && except2 == false);
CHECK(except3 == true && except4 == false);
}
{
any i4 = 4;
any i5 = 5;
any f6 = 6.0f;
any big1 = big_type();
any big2 = big_type();
any big3 = big_type();
CHECK(any_cast<int>(&i4) != nullptr);
CHECK(any_cast<float>(&i4) == nullptr);
CHECK(any_cast<int>(i5) == 5);
CHECK(any_cast<float>(f6) == 6.0f);
CHECK(any_cast<big_type>(big1).check()
&& any_cast<big_type>(big2).check()
&& any_cast<big_type>(big3).check());
}
{
std::shared_ptr<int> ptr_count(new int);
std::weak_ptr<int> weak = ptr_count;
any p0 = 0;
CHECK(weak.use_count() == 1);
any p1 = ptr_count;
CHECK(weak.use_count() == 2);
any p2 = p1;
CHECK(weak.use_count() == 3);
p0 = p1;
CHECK(weak.use_count() == 4);
p0 = 0;
CHECK(weak.use_count() == 3);
p0 = std::move(p1);
CHECK(weak.use_count() == 3);
p0.swap(p1);
CHECK(weak.use_count() == 3);
p0 = 0;
CHECK(weak.use_count() == 3);
p1.clear();
CHECK(weak.use_count() == 2);
p2 = any(big_type());
CHECK(weak.use_count() == 1);
p1 = ptr_count;
CHECK(weak.use_count() == 2);
ptr_count = nullptr;
CHECK(weak.use_count() == 1);
p1 = any();
CHECK(weak.use_count() == 0);
}
{
auto is_stack_allocated = [](const any& a, const void* obj1) {
uintptr_t a_ptr = (uintptr_t)(&a);
uintptr_t obj = (uintptr_t)(obj1);
return (obj >= a_ptr && obj < a_ptr + sizeof(any));
};
//static_assert(sizeof(std::unique_ptr<big_type>) <= sizeof(void*) * 1, "unique_ptr too big");
static_assert(sizeof(std::shared_ptr<big_type>) <= sizeof(void*) * 2, "shared_ptr too big");
any i = 400;
any f = 400.0f;
//any unique = std::unique_ptr<big_type>(); -- must be copy constructible
any shared = std::shared_ptr<big_type>();
any rawptr = (void*)(nullptr);
any big = big_type();
any w2 = words<2>();
any w3 = words<3>();
CHECK(is_stack_allocated(i, any_cast<int>(&i)));
CHECK(is_stack_allocated(f, any_cast<float>(&f)));
CHECK(is_stack_allocated(rawptr, any_cast<void*>(&rawptr)));
//CHECK(is_stack_allocated(unique, any_cast<std::unique_ptr<big_type>>(&unique)));
CHECK(is_stack_allocated(shared, any_cast<std::shared_ptr<big_type>>(&shared)));
CHECK(!is_stack_allocated(big, any_cast<big_type>(&big)));
CHECK(is_stack_allocated(w2, any_cast<words<2>>(&w2)));
CHECK(!is_stack_allocated(w3, any_cast<words<3>>(&w3)));
// Regression test for GitHub Issue #1
any r1 = regression1_type();
CHECK(is_stack_allocated(r1, any_cast<const regression1_type>(&r1)));
}
// correctly stored decayed and retrieved in decayed form
{
const int i = 42;
any a = i;
// retrieve
CHECK(any_cast<int>(&a) != nullptr);
CHECK(any_cast<const int>(&a) != nullptr);
#ifndef ANY_IMPL_NO_EXCEPTIONS
// must not throw
bool except1 = false, except2 = false, except3 = false;
// same with reference to any
try {
any_cast<int>(a);
}
catch(const bad_any_cast&) {
except1 = true;
}
try {
any_cast<const int>(a);
}
catch(const bad_any_cast&) {
except2 = true;
}
try {
any_cast<const int>(std::move(a));
}
catch(const bad_any_cast&) {
except3 = true;
}
CHECK(except1 == false);
CHECK(except2 == false);
CHECK(except3 == false);
#endif
}
{
bool except1 = false, except2 = false;
auto big_any = shared_test_lib::createBigData();
auto small_any = shared_test_lib::createSmallData();
try {
any_cast<shared_test_lib::big_data>(big_any);
} catch (const bad_any_cast &) {
except1 = true;
}
try {
any_cast<shared_test_lib::small_data>(small_any);
} catch (const bad_any_cast &) {
except2 = true;
}
#ifndef ANY_IMPL_NO_RTTI
CHECK(except1 == false);
CHECK(except2 == false);
#else
CHECK(except1 == true);
CHECK(except2 == true);
#endif
}
}