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
base()42 base(): use_count_(0)
43 {
44 }
45
~base()46 virtual ~base()
47 {
48 }
49
50 public:
51
use_count() const52 long use_count() const
53 {
54 return use_count_;
55 }
56
add_ref()57 void add_ref()
58 {
59 ++addref_release_calls;
60 ++use_count_;
61 }
62
release()63 void release()
64 {
65 ++addref_release_calls;
66 if(--use_count_ == 0) delete this;
67 }
68 };
69
intrusive_ptr_add_ref(N::base * p)70 inline void intrusive_ptr_add_ref(N::base *p)
71 { p->add_ref(); }
72
intrusive_ptr_release(N::base * p)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
f(X &)91 void f(X &)
92 {
93 }
94
test()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
default_constructor()107 void default_constructor()
108 {
109 boost::interprocess::intrusive_ptr<X, VP> px;
110 BOOST_TEST(px.get() == 0);
111 }
112
pointer_constructor()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.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
copy_constructor()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
move_constructor()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(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
test()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
test()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
copy_assignment()247 void copy_assignment()
248 {
249 }
250
move_assignment()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(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
conversion_assignment()271 void conversion_assignment()
272 {
273 }
274
pointer_assignment()275 void pointer_assignment()
276 {
277 }
278
test()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
test()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
test()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(px2);
328
329 BOOST_TEST(px.get() == 0);
330 BOOST_TEST(px2.get() == 0);
331
332 ::boost::adl_move_swap(px, 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(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(px, 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(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(px, 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>
test2(boost::interprocess::intrusive_ptr<T,VP> const & p,boost::interprocess::intrusive_ptr<U,VP> const & q)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>
test3(boost::interprocess::intrusive_ptr<T,VP> const & p,boost::interprocess::intrusive_ptr<T,VP> const & q)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
test()417 void test()
418 {
419 {
420 boost::interprocess::intrusive_ptr<X, VP> px;
421 test3(px, px);
422
423 boost::interprocess::intrusive_ptr<X, VP> px2;
424 test3(px, px2);
425
426 boost::interprocess::intrusive_ptr<X, VP> px3(px);
427 test3(px3, px3);
428 test3(px, 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(px, px2);
436 test3(px2, px2);
437
438 boost::interprocess::intrusive_ptr<X, VP> px3(new X);
439 test3(px2, px3);
440
441 boost::interprocess::intrusive_ptr<X, VP> px4(px2);
442 test3(px2, px4);
443 test3(px4, 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(px, py);
451
452 boost::interprocess::intrusive_ptr<X, VP> px2(py);
453 test2(px2, py);
454 test3(px, px2);
455 test3(px2, px2);
456 }
457 }
458
459 } // namespace n_comparison
460
461 namespace n_static_cast
462 {
463
test()464 void test()
465 {
466 }
467
468 } // namespace n_static_cast
469
470 namespace n_dynamic_cast
471 {
472
test()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
test()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
foo()505 foo(): m_self(this)
506 {
507 }
508
suicide()509 void suicide()
510 {
511 m_self = 0;
512 }
513
514 private:
515
516 boost::interprocess::intrusive_ptr<foo, VP> m_self;
517 };
518
test()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
main()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