////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Peter Dimov 2002-2005. // (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include typedef boost::interprocess::offset_ptr VP; namespace { int addref_release_calls = 0; } namespace N { class base { private: int use_count_; base(base const &); base & operator=(base const &); protected: base(): use_count_(0) { } virtual ~base() { } public: long use_count() const { return use_count_; } void add_ref() { ++addref_release_calls; ++use_count_; } void release() { ++addref_release_calls; if(--use_count_ == 0) delete this; } }; inline void intrusive_ptr_add_ref(N::base *p) { p->add_ref(); } inline void intrusive_ptr_release(N::base *p) { p->release(); } } // namespace N struct X: public virtual N::base { }; struct Y: public X { }; // namespace n_element_type { void f(X &) { } void test() { typedef boost::interprocess::intrusive_ptr::element_type T; T t; f(t); } } // namespace n_element_type namespace n_constructors { void default_constructor() { boost::interprocess::intrusive_ptr px; BOOST_TEST(px.get() == 0); } void pointer_constructor() { { boost::interprocess::intrusive_ptr px(0); BOOST_TEST(px.get() == 0); } { boost::interprocess::intrusive_ptr px(0, false); BOOST_TEST(px.get() == 0); } { boost::interprocess::offset_ptr p = new X; BOOST_TEST(p->use_count() == 0); boost::interprocess::intrusive_ptr px(p); BOOST_TEST(px.get() == p); BOOST_TEST(px->use_count() == 1); } { boost::interprocess::offset_ptr p = new X; BOOST_TEST(p->use_count() == 0); intrusive_ptr_add_ref(p.get()); BOOST_TEST(p->use_count() == 1); boost::interprocess::intrusive_ptr px(p, false); BOOST_TEST(px.get() == p); BOOST_TEST(px->use_count() == 1); } } void copy_constructor() { { boost::interprocess::intrusive_ptr px; boost::interprocess::intrusive_ptr px2(px); BOOST_TEST(px2.get() == px.get()); } { boost::interprocess::intrusive_ptr py; boost::interprocess::intrusive_ptr px(py); BOOST_TEST(px.get() == py.get()); } { boost::interprocess::intrusive_ptr px(0); boost::interprocess::intrusive_ptr px2(px); BOOST_TEST(px2.get() == px.get()); } { boost::interprocess::intrusive_ptr py(0); boost::interprocess::intrusive_ptr px(py); BOOST_TEST(px.get() == py.get()); } { boost::interprocess::intrusive_ptr px(0, false); boost::interprocess::intrusive_ptr px2(px); BOOST_TEST(px2.get() == px.get()); } { boost::interprocess::intrusive_ptr py(0, false); boost::interprocess::intrusive_ptr px(py); BOOST_TEST(px.get() == py.get()); } { boost::interprocess::intrusive_ptr px(new X); boost::interprocess::intrusive_ptr px2(px); BOOST_TEST(px2.get() == px.get()); } { boost::interprocess::intrusive_ptr py(new Y); boost::interprocess::intrusive_ptr px(py); BOOST_TEST(px.get() == py.get()); } } void move_constructor() { { int prev_addref_release_calls = addref_release_calls; X* x = new X(); boost::interprocess::intrusive_ptr px(x); BOOST_TEST(addref_release_calls == prev_addref_release_calls + 1); //static_assert(std::is_nothrow_move_constructible< boost::interprocess::intrusive_ptr >::value, "test instrusive_ptr is nothrow move constructible"); boost::interprocess::intrusive_ptr px2(boost::move(px)); BOOST_TEST(px2.get() == x); BOOST_TEST(!px.get()); BOOST_TEST(px2->use_count() == 1); BOOST_TEST(addref_release_calls == prev_addref_release_calls + 1); } } void test() { default_constructor(); pointer_constructor(); copy_constructor(); move_constructor(); } } // namespace n_constructors namespace n_destructor { void test() { boost::interprocess::intrusive_ptr px(new X); BOOST_TEST(px->use_count() == 1); { boost::interprocess::intrusive_ptr px2(px); BOOST_TEST(px->use_count() == 2); } BOOST_TEST(px->use_count() == 1); } } // namespace n_destructor namespace n_assignment { void copy_assignment() { } void move_assignment() { { int prev_addref_release_calls = addref_release_calls; X* x = new X(); boost::interprocess::intrusive_ptr px(x); BOOST_TEST(px->use_count() == 1); BOOST_TEST(addref_release_calls == prev_addref_release_calls + 1); //static_assert(std::is_nothrow_move_assignable< boost::interprocess::intrusive_ptr >::value, "test if nothrow move assignable "); boost::interprocess::intrusive_ptr px2; px2 = boost::move(px); BOOST_TEST(px2.get() == x); BOOST_TEST(!px.get()); BOOST_TEST(px2->use_count() == 1); BOOST_TEST(addref_release_calls == prev_addref_release_calls + 1); } } void conversion_assignment() { } void pointer_assignment() { } void test() { copy_assignment(); conversion_assignment(); pointer_assignment(); move_assignment(); } } // namespace n_assignment namespace n_access { void test() { { boost::interprocess::intrusive_ptr px; BOOST_TEST(px? false: true); BOOST_TEST(!px); } { boost::interprocess::intrusive_ptr px(0); BOOST_TEST(px? false: true); BOOST_TEST(!px); } { boost::interprocess::intrusive_ptr px (boost::interprocess::offset_ptr(new X)); BOOST_TEST(px? true: false); BOOST_TEST(!!px); BOOST_TEST(&*px == boost::interprocess::ipcdetail::to_raw_pointer(px.get())); BOOST_TEST(px.operator ->() == px.get()); } } } // namespace n_access namespace n_swap { void test() { { boost::interprocess::intrusive_ptr px; boost::interprocess::intrusive_ptr px2; px.swap(px2); BOOST_TEST(px.get() == 0); BOOST_TEST(px2.get() == 0); ::boost::adl_move_swap(px, px2); BOOST_TEST(px.get() == 0); BOOST_TEST(px2.get() == 0); } { boost::interprocess::offset_ptr p = new X; boost::interprocess::intrusive_ptr px; boost::interprocess::intrusive_ptr px2(p); boost::interprocess::intrusive_ptr px3(px2); px.swap(px2); BOOST_TEST(px.get() == p); BOOST_TEST(px->use_count() == 2); BOOST_TEST(px2.get() == 0); BOOST_TEST(px3.get() == p); BOOST_TEST(px3->use_count() == 2); ::boost::adl_move_swap(px, px2); BOOST_TEST(px.get() == 0); BOOST_TEST(px2.get() == p); BOOST_TEST(px2->use_count() == 2); BOOST_TEST(px3.get() == p); BOOST_TEST(px3->use_count() == 2); } { boost::interprocess::offset_ptr p1 = new X; boost::interprocess::offset_ptr p2 = new X; boost::interprocess::intrusive_ptr px(p1); boost::interprocess::intrusive_ptr px2(p2); boost::interprocess::intrusive_ptr px3(px2); px.swap(px2); BOOST_TEST(px.get() == p2); BOOST_TEST(px->use_count() == 2); BOOST_TEST(px2.get() == p1); BOOST_TEST(px2->use_count() == 1); BOOST_TEST(px3.get() == p2); BOOST_TEST(px3->use_count() == 2); ::boost::adl_move_swap(px, px2); BOOST_TEST(px.get() == p1); BOOST_TEST(px->use_count() == 1); BOOST_TEST(px2.get() == p2); BOOST_TEST(px2->use_count() == 2); BOOST_TEST(px3.get() == p2); BOOST_TEST(px3->use_count() == 2); } } } // namespace n_swap namespace n_comparison { template void test2(boost::interprocess::intrusive_ptr const & p, boost::interprocess::intrusive_ptr const & q) { BOOST_TEST((p == q) == (p.get() == q.get())); BOOST_TEST((p != q) == (p.get() != q.get())); } template void test3(boost::interprocess::intrusive_ptr const & p, boost::interprocess::intrusive_ptr const & q) { BOOST_TEST((p == q) == (p.get() == q.get())); BOOST_TEST((p.get() == q) == (p.get() == q.get())); BOOST_TEST((p == q.get()) == (p.get() == q.get())); BOOST_TEST((p != q) == (p.get() != q.get())); BOOST_TEST((p.get() != q) == (p.get() != q.get())); BOOST_TEST((p != q.get()) == (p.get() != q.get())); // 'less' moved here as a g++ 2.9x parse error workaround std::less > less; BOOST_TEST((p < q) == less(p.get(), q.get())); } void test() { { boost::interprocess::intrusive_ptr px; test3(px, px); boost::interprocess::intrusive_ptr px2; test3(px, px2); boost::interprocess::intrusive_ptr px3(px); test3(px3, px3); test3(px, px3); } { boost::interprocess::intrusive_ptr px; boost::interprocess::intrusive_ptr px2(new X); test3(px, px2); test3(px2, px2); boost::interprocess::intrusive_ptr px3(new X); test3(px2, px3); boost::interprocess::intrusive_ptr px4(px2); test3(px2, px4); test3(px4, px4); } { boost::interprocess::intrusive_ptr px(new X); boost::interprocess::intrusive_ptr py(new Y); test2(px, py); boost::interprocess::intrusive_ptr px2(py); test2(px2, py); test3(px, px2); test3(px2, px2); } } } // namespace n_comparison namespace n_static_cast { void test() { } } // namespace n_static_cast namespace n_dynamic_cast { void test() { } } // namespace n_dynamic_cast namespace n_transitive { struct X: public N::base { boost::interprocess::intrusive_ptr next; }; void test() { boost::interprocess::intrusive_ptr p(new X); p->next = boost::interprocess::intrusive_ptr(new X); BOOST_TEST(!p->next->next); p = p->next; BOOST_TEST(!p->next); } } // namespace n_transitive namespace n_report_1 { class foo: public N::base { public: foo(): m_self(this) { } void suicide() { m_self = 0; } private: boost::interprocess::intrusive_ptr m_self; }; void test() { boost::interprocess::offset_ptr foo_ptr = new foo; foo_ptr->suicide(); } } // namespace n_report_1 int main() { n_element_type::test(); n_constructors::test(); n_destructor::test(); n_assignment::test(); n_access::test(); n_swap::test(); n_comparison::test(); n_static_cast::test(); n_dynamic_cast::test(); n_transitive::test(); n_report_1::test(); return boost::report_errors(); } #include