• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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