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
22typedef boost::interprocess::offset_ptr<void> VP;
23
24namespace {
25 int addref_release_calls = 0;
26}
27
28namespace N
29{
30
31class 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
70inline void intrusive_ptr_add_ref(N::base *p)
71{ p->add_ref(); }
72
73inline void intrusive_ptr_release(N::base *p)
74{ p->release(); }
75
76} // namespace N
77
78struct X: public virtual N::base
79{
80};
81
82struct Y: public X
83{
84};
85
86//
87
88namespace n_element_type
89{
90
91void f(X &)
92{
93}
94
95void 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
104namespace n_constructors
105{
106
107void default_constructor()
108{
109 boost::interprocess::intrusive_ptr<X, VP> px;
110 BOOST_TEST(px.get() == 0);
111}
112
113void 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
147void 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
198void 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
216void test()
217{
218 default_constructor();
219 pointer_constructor();
220 copy_constructor();
221 move_constructor();
222}
223
224} // namespace n_constructors
225
226namespace n_destructor
227{
228
229void 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
244namespace n_assignment
245{
246
247void copy_assignment()
248{
249}
250
251void 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
271void conversion_assignment()
272{
273}
274
275void pointer_assignment()
276{
277}
278
279void test()
280{
281 copy_assignment();
282 conversion_assignment();
283 pointer_assignment();
284 move_assignment();
285}
286
287} // namespace n_assignment
288
289namespace n_access
290{
291
292void 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
318namespace n_swap
319{
320
321void 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
390namespace n_comparison
391{
392
393template<class T, class U, class VP>
394void 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
401template<class T, class VP>
402void 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
417void 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
461namespace n_static_cast
462{
463
464void test()
465{
466}
467
468} // namespace n_static_cast
469
470namespace n_dynamic_cast
471{
472
473void test()
474{
475}
476
477} // namespace n_dynamic_cast
478
479namespace n_transitive
480{
481
482struct X: public N::base
483{
484 boost::interprocess::intrusive_ptr<X, VP> next;
485};
486
487void 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
498namespace n_report_1
499{
500
501class 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
519void test()
520{
521 boost::interprocess::offset_ptr<foo> foo_ptr = new foo;
522 foo_ptr->suicide();
523}
524
525} // namespace n_report_1
526
527int 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

source code of boost/libs/interprocess/test/intrusive_ptr_test.cpp