1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // (C) Copyright Peter Dimov 2002-2005. |
4 | // (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost |
5 | // Software License, Version 1.0. (See accompanying file |
6 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | // |
8 | // See http://www.boost.org/libs/interprocess for documentation. |
9 | // |
10 | ////////////////////////////////////////////////////////////////////////////// |
11 | |
12 | #include <boost/interprocess/offset_ptr.hpp> |
13 | #include <boost/interprocess/smart_ptr/intrusive_ptr.hpp> |
14 | #include <boost/interprocess/managed_shared_memory.hpp> |
15 | |
16 | #include <boost/core/lightweight_test.hpp> |
17 | #include <boost/config.hpp> |
18 | #include <boost/move/adl_move_swap.hpp> |
19 | #include <boost/move/core.hpp> |
20 | #include <functional> |
21 | |
22 | typedef boost::interprocess::offset_ptr<void> VP; |
23 | |
24 | namespace { |
25 | int addref_release_calls = 0; |
26 | } |
27 | |
28 | namespace N |
29 | { |
30 | |
31 | class base |
32 | { |
33 | private: |
34 | |
35 | int use_count_; |
36 | |
37 | base(base const &); |
38 | base & operator=(base const &); |
39 | |
40 | protected: |
41 | |
42 | base(): use_count_(0) |
43 | { |
44 | } |
45 | |
46 | virtual ~base() |
47 | { |
48 | } |
49 | |
50 | public: |
51 | |
52 | long use_count() const |
53 | { |
54 | return use_count_; |
55 | } |
56 | |
57 | void add_ref() |
58 | { |
59 | ++addref_release_calls; |
60 | ++use_count_; |
61 | } |
62 | |
63 | void release() |
64 | { |
65 | ++addref_release_calls; |
66 | if(--use_count_ == 0) delete this; |
67 | } |
68 | }; |
69 | |
70 | inline void intrusive_ptr_add_ref(N::base *p) |
71 | { p->add_ref(); } |
72 | |
73 | inline void intrusive_ptr_release(N::base *p) |
74 | { p->release(); } |
75 | |
76 | } // namespace N |
77 | |
78 | struct X: public virtual N::base |
79 | { |
80 | }; |
81 | |
82 | struct Y: public X |
83 | { |
84 | }; |
85 | |
86 | // |
87 | |
88 | namespace n_element_type |
89 | { |
90 | |
91 | void f(X &) |
92 | { |
93 | } |
94 | |
95 | void test() |
96 | { |
97 | typedef boost::interprocess::intrusive_ptr<X, VP>::element_type T; |
98 | T t; |
99 | f(t); |
100 | } |
101 | |
102 | } // namespace n_element_type |
103 | |
104 | namespace n_constructors |
105 | { |
106 | |
107 | void default_constructor() |
108 | { |
109 | boost::interprocess::intrusive_ptr<X, VP> px; |
110 | BOOST_TEST(px.get() == 0); |
111 | } |
112 | |
113 | void pointer_constructor() |
114 | { |
115 | { |
116 | boost::interprocess::intrusive_ptr<X, VP> px(0); |
117 | BOOST_TEST(px.get() == 0); |
118 | } |
119 | |
120 | { |
121 | boost::interprocess::intrusive_ptr<X, VP> px(0, false); |
122 | BOOST_TEST(px.get() == 0); |
123 | } |
124 | |
125 | { |
126 | boost::interprocess::offset_ptr<X> p = new X; |
127 | BOOST_TEST(p->use_count() == 0); |
128 | |
129 | boost::interprocess::intrusive_ptr<X, VP> px(p); |
130 | BOOST_TEST(px.get() == p); |
131 | BOOST_TEST(px->use_count() == 1); |
132 | } |
133 | |
134 | { |
135 | boost::interprocess::offset_ptr<X> p = new X; |
136 | BOOST_TEST(p->use_count() == 0); |
137 | |
138 | intrusive_ptr_add_ref(p: p.get()); |
139 | BOOST_TEST(p->use_count() == 1); |
140 | |
141 | boost::interprocess::intrusive_ptr<X, VP> px(p, false); |
142 | BOOST_TEST(px.get() == p); |
143 | BOOST_TEST(px->use_count() == 1); |
144 | } |
145 | } |
146 | |
147 | void copy_constructor() |
148 | { |
149 | { |
150 | boost::interprocess::intrusive_ptr<X, VP> px; |
151 | boost::interprocess::intrusive_ptr<X, VP> px2(px); |
152 | BOOST_TEST(px2.get() == px.get()); |
153 | } |
154 | |
155 | { |
156 | boost::interprocess::intrusive_ptr<Y, VP> py; |
157 | boost::interprocess::intrusive_ptr<X, VP> px(py); |
158 | BOOST_TEST(px.get() == py.get()); |
159 | } |
160 | |
161 | { |
162 | boost::interprocess::intrusive_ptr<X, VP> px(0); |
163 | boost::interprocess::intrusive_ptr<X, VP> px2(px); |
164 | BOOST_TEST(px2.get() == px.get()); |
165 | } |
166 | |
167 | { |
168 | boost::interprocess::intrusive_ptr<Y, VP> py(0); |
169 | boost::interprocess::intrusive_ptr<X, VP> px(py); |
170 | BOOST_TEST(px.get() == py.get()); |
171 | } |
172 | |
173 | { |
174 | boost::interprocess::intrusive_ptr<X, VP> px(0, false); |
175 | boost::interprocess::intrusive_ptr<X, VP> px2(px); |
176 | BOOST_TEST(px2.get() == px.get()); |
177 | } |
178 | |
179 | { |
180 | boost::interprocess::intrusive_ptr<Y, VP> py(0, false); |
181 | boost::interprocess::intrusive_ptr<X, VP> px(py); |
182 | BOOST_TEST(px.get() == py.get()); |
183 | } |
184 | |
185 | { |
186 | boost::interprocess::intrusive_ptr<X, VP> px(new X); |
187 | boost::interprocess::intrusive_ptr<X, VP> px2(px); |
188 | BOOST_TEST(px2.get() == px.get()); |
189 | } |
190 | |
191 | { |
192 | boost::interprocess::intrusive_ptr<Y, VP> py(new Y); |
193 | boost::interprocess::intrusive_ptr<X, VP> px(py); |
194 | BOOST_TEST(px.get() == py.get()); |
195 | } |
196 | } |
197 | |
198 | void move_constructor() |
199 | { |
200 | { |
201 | int prev_addref_release_calls = addref_release_calls; |
202 | X* x = new X(); |
203 | boost::interprocess::intrusive_ptr<X, VP> px(x); |
204 | BOOST_TEST(addref_release_calls == prev_addref_release_calls + 1); |
205 | |
206 | //static_assert(std::is_nothrow_move_constructible< boost::interprocess::intrusive_ptr<X, VP> >::value, "test instrusive_ptr is nothrow move constructible"); |
207 | |
208 | boost::interprocess::intrusive_ptr<X, VP> px2(boost::move(t&: px)); |
209 | BOOST_TEST(px2.get() == x); |
210 | BOOST_TEST(!px.get()); |
211 | BOOST_TEST(px2->use_count() == 1); |
212 | BOOST_TEST(addref_release_calls == prev_addref_release_calls + 1); |
213 | } |
214 | } |
215 | |
216 | void test() |
217 | { |
218 | default_constructor(); |
219 | pointer_constructor(); |
220 | copy_constructor(); |
221 | move_constructor(); |
222 | } |
223 | |
224 | } // namespace n_constructors |
225 | |
226 | namespace n_destructor |
227 | { |
228 | |
229 | void test() |
230 | { |
231 | boost::interprocess::intrusive_ptr<X, VP> px(new X); |
232 | BOOST_TEST(px->use_count() == 1); |
233 | |
234 | { |
235 | boost::interprocess::intrusive_ptr<X, VP> px2(px); |
236 | BOOST_TEST(px->use_count() == 2); |
237 | } |
238 | |
239 | BOOST_TEST(px->use_count() == 1); |
240 | } |
241 | |
242 | } // namespace n_destructor |
243 | |
244 | namespace n_assignment |
245 | { |
246 | |
247 | void copy_assignment() |
248 | { |
249 | } |
250 | |
251 | void move_assignment() |
252 | { |
253 | { |
254 | int prev_addref_release_calls = addref_release_calls; |
255 | X* x = new X(); |
256 | boost::interprocess::intrusive_ptr<X, VP> px(x); |
257 | BOOST_TEST(px->use_count() == 1); |
258 | BOOST_TEST(addref_release_calls == prev_addref_release_calls + 1); |
259 | |
260 | //static_assert(std::is_nothrow_move_assignable< boost::interprocess::intrusive_ptr<X, VP> >::value, "test if nothrow move assignable "); |
261 | |
262 | boost::interprocess::intrusive_ptr<X, VP> px2; |
263 | px2 = boost::move(t&: px); |
264 | BOOST_TEST(px2.get() == x); |
265 | BOOST_TEST(!px.get()); |
266 | BOOST_TEST(px2->use_count() == 1); |
267 | BOOST_TEST(addref_release_calls == prev_addref_release_calls + 1); |
268 | } |
269 | } |
270 | |
271 | void conversion_assignment() |
272 | { |
273 | } |
274 | |
275 | void pointer_assignment() |
276 | { |
277 | } |
278 | |
279 | void test() |
280 | { |
281 | copy_assignment(); |
282 | conversion_assignment(); |
283 | pointer_assignment(); |
284 | move_assignment(); |
285 | } |
286 | |
287 | } // namespace n_assignment |
288 | |
289 | namespace n_access |
290 | { |
291 | |
292 | void test() |
293 | { |
294 | { |
295 | boost::interprocess::intrusive_ptr<X, VP> px; |
296 | BOOST_TEST(px? false: true); |
297 | BOOST_TEST(!px); |
298 | } |
299 | |
300 | { |
301 | boost::interprocess::intrusive_ptr<X, VP> px(0); |
302 | BOOST_TEST(px? false: true); |
303 | BOOST_TEST(!px); |
304 | } |
305 | |
306 | { |
307 | boost::interprocess::intrusive_ptr<X, VP> px |
308 | (boost::interprocess::offset_ptr<X>(new X)); |
309 | BOOST_TEST(px? true: false); |
310 | BOOST_TEST(!!px); |
311 | BOOST_TEST(&*px == boost::interprocess::ipcdetail::to_raw_pointer(px.get())); |
312 | BOOST_TEST(px.operator ->() == px.get()); |
313 | } |
314 | } |
315 | |
316 | } // namespace n_access |
317 | |
318 | namespace n_swap |
319 | { |
320 | |
321 | void test() |
322 | { |
323 | { |
324 | boost::interprocess::intrusive_ptr<X, VP> px; |
325 | boost::interprocess::intrusive_ptr<X, VP> px2; |
326 | |
327 | px.swap(rhs&: px2); |
328 | |
329 | BOOST_TEST(px.get() == 0); |
330 | BOOST_TEST(px2.get() == 0); |
331 | |
332 | ::boost::adl_move_swap(x&: px, y&: px2); |
333 | |
334 | BOOST_TEST(px.get() == 0); |
335 | BOOST_TEST(px2.get() == 0); |
336 | } |
337 | |
338 | { |
339 | boost::interprocess::offset_ptr<X> p = new X; |
340 | boost::interprocess::intrusive_ptr<X, VP> px; |
341 | boost::interprocess::intrusive_ptr<X, VP> px2(p); |
342 | boost::interprocess::intrusive_ptr<X, VP> px3(px2); |
343 | |
344 | px.swap(rhs&: px2); |
345 | |
346 | BOOST_TEST(px.get() == p); |
347 | BOOST_TEST(px->use_count() == 2); |
348 | BOOST_TEST(px2.get() == 0); |
349 | BOOST_TEST(px3.get() == p); |
350 | BOOST_TEST(px3->use_count() == 2); |
351 | |
352 | ::boost::adl_move_swap(x&: px, y&: px2); |
353 | |
354 | BOOST_TEST(px.get() == 0); |
355 | BOOST_TEST(px2.get() == p); |
356 | BOOST_TEST(px2->use_count() == 2); |
357 | BOOST_TEST(px3.get() == p); |
358 | BOOST_TEST(px3->use_count() == 2); |
359 | } |
360 | |
361 | { |
362 | boost::interprocess::offset_ptr<X> p1 = new X; |
363 | boost::interprocess::offset_ptr<X> p2 = new X; |
364 | boost::interprocess::intrusive_ptr<X, VP> px(p1); |
365 | boost::interprocess::intrusive_ptr<X, VP> px2(p2); |
366 | boost::interprocess::intrusive_ptr<X, VP> px3(px2); |
367 | |
368 | px.swap(rhs&: px2); |
369 | |
370 | BOOST_TEST(px.get() == p2); |
371 | BOOST_TEST(px->use_count() == 2); |
372 | BOOST_TEST(px2.get() == p1); |
373 | BOOST_TEST(px2->use_count() == 1); |
374 | BOOST_TEST(px3.get() == p2); |
375 | BOOST_TEST(px3->use_count() == 2); |
376 | |
377 | ::boost::adl_move_swap(x&: px, y&: px2); |
378 | |
379 | BOOST_TEST(px.get() == p1); |
380 | BOOST_TEST(px->use_count() == 1); |
381 | BOOST_TEST(px2.get() == p2); |
382 | BOOST_TEST(px2->use_count() == 2); |
383 | BOOST_TEST(px3.get() == p2); |
384 | BOOST_TEST(px3->use_count() == 2); |
385 | } |
386 | } |
387 | |
388 | } // namespace n_swap |
389 | |
390 | namespace n_comparison |
391 | { |
392 | |
393 | template<class T, class U, class VP> |
394 | void test2(boost::interprocess::intrusive_ptr<T, VP> const & p, |
395 | boost::interprocess::intrusive_ptr<U, VP> const & q) |
396 | { |
397 | BOOST_TEST((p == q) == (p.get() == q.get())); |
398 | BOOST_TEST((p != q) == (p.get() != q.get())); |
399 | } |
400 | |
401 | template<class T, class VP> |
402 | void test3(boost::interprocess::intrusive_ptr<T, VP> const & p, |
403 | boost::interprocess::intrusive_ptr<T, VP> const & q) |
404 | { |
405 | BOOST_TEST((p == q) == (p.get() == q.get())); |
406 | BOOST_TEST((p.get() == q) == (p.get() == q.get())); |
407 | BOOST_TEST((p == q.get()) == (p.get() == q.get())); |
408 | BOOST_TEST((p != q) == (p.get() != q.get())); |
409 | BOOST_TEST((p.get() != q) == (p.get() != q.get())); |
410 | BOOST_TEST((p != q.get()) == (p.get() != q.get())); |
411 | |
412 | // 'less' moved here as a g++ 2.9x parse error workaround |
413 | std::less<boost::interprocess::offset_ptr<T> > less; |
414 | BOOST_TEST((p < q) == less(p.get(), q.get())); |
415 | } |
416 | |
417 | void test() |
418 | { |
419 | { |
420 | boost::interprocess::intrusive_ptr<X, VP> px; |
421 | test3(p: px, q: px); |
422 | |
423 | boost::interprocess::intrusive_ptr<X, VP> px2; |
424 | test3(p: px, q: px2); |
425 | |
426 | boost::interprocess::intrusive_ptr<X, VP> px3(px); |
427 | test3(p: px3, q: px3); |
428 | test3(p: px, q: px3); |
429 | } |
430 | |
431 | { |
432 | boost::interprocess::intrusive_ptr<X, VP> px; |
433 | |
434 | boost::interprocess::intrusive_ptr<X, VP> px2(new X); |
435 | test3(p: px, q: px2); |
436 | test3(p: px2, q: px2); |
437 | |
438 | boost::interprocess::intrusive_ptr<X, VP> px3(new X); |
439 | test3(p: px2, q: px3); |
440 | |
441 | boost::interprocess::intrusive_ptr<X, VP> px4(px2); |
442 | test3(p: px2, q: px4); |
443 | test3(p: px4, q: px4); |
444 | } |
445 | |
446 | { |
447 | boost::interprocess::intrusive_ptr<X, VP> px(new X); |
448 | |
449 | boost::interprocess::intrusive_ptr<Y, VP> py(new Y); |
450 | test2(p: px, q: py); |
451 | |
452 | boost::interprocess::intrusive_ptr<X, VP> px2(py); |
453 | test2(p: px2, q: py); |
454 | test3(p: px, q: px2); |
455 | test3(p: px2, q: px2); |
456 | } |
457 | } |
458 | |
459 | } // namespace n_comparison |
460 | |
461 | namespace n_static_cast |
462 | { |
463 | |
464 | void test() |
465 | { |
466 | } |
467 | |
468 | } // namespace n_static_cast |
469 | |
470 | namespace n_dynamic_cast |
471 | { |
472 | |
473 | void test() |
474 | { |
475 | } |
476 | |
477 | } // namespace n_dynamic_cast |
478 | |
479 | namespace n_transitive |
480 | { |
481 | |
482 | struct X: public N::base |
483 | { |
484 | boost::interprocess::intrusive_ptr<X, VP> next; |
485 | }; |
486 | |
487 | void test() |
488 | { |
489 | boost::interprocess::intrusive_ptr<X, VP> p(new X); |
490 | p->next = boost::interprocess::intrusive_ptr<X, VP>(new X); |
491 | BOOST_TEST(!p->next->next); |
492 | p = p->next; |
493 | BOOST_TEST(!p->next); |
494 | } |
495 | |
496 | } // namespace n_transitive |
497 | |
498 | namespace n_report_1 |
499 | { |
500 | |
501 | class foo: public N::base |
502 | { |
503 | public: |
504 | |
505 | foo(): m_self(this) |
506 | { |
507 | } |
508 | |
509 | void suicide() |
510 | { |
511 | m_self = 0; |
512 | } |
513 | |
514 | private: |
515 | |
516 | boost::interprocess::intrusive_ptr<foo, VP> m_self; |
517 | }; |
518 | |
519 | void test() |
520 | { |
521 | boost::interprocess::offset_ptr<foo> foo_ptr = new foo; |
522 | foo_ptr->suicide(); |
523 | } |
524 | |
525 | } // namespace n_report_1 |
526 | |
527 | int main() |
528 | { |
529 | n_element_type::test(); |
530 | n_constructors::test(); |
531 | n_destructor::test(); |
532 | n_assignment::test(); |
533 | n_access::test(); |
534 | n_swap::test(); |
535 | n_comparison::test(); |
536 | n_static_cast::test(); |
537 | n_dynamic_cast::test(); |
538 | |
539 | n_transitive::test(); |
540 | n_report_1::test(); |
541 | |
542 | return boost::report_errors(); |
543 | } |
544 | |