diff --git a/doc/smart_ptr.adoc b/doc/smart_ptr.adoc index d3210d7..3c299c3 100644 --- a/doc/smart_ptr.adoc +++ b/doc/smart_ptr.adoc @@ -37,6 +37,8 @@ include::smart_ptr/intrusive_ptr.adoc[] include::smart_ptr/intrusive_ref_counter.adoc[] +include::smart_ptr/local_shared_ptr.adoc[] + include::smart_ptr/pointer_cast.adoc[] include::smart_ptr/pointer_to_other.adoc[] diff --git a/doc/smart_ptr/introduction.adoc b/doc/smart_ptr/introduction.adoc index 2154014..ff51823 100644 --- a/doc/smart_ptr/introduction.adoc +++ b/doc/smart_ptr/introduction.adoc @@ -24,13 +24,14 @@ deletion of the object when it is no longer needed. As such, they are examples o acquisition is initialization" idiom described in Bjarne Stroustrup's "The C++ Programming Language", 3rd edition, Section 14.4, Resource Management. -This library provides five smart pointer class templates: +This library provides six smart pointer class templates: * `<>`, used to contain ownership of a dynamically allocated object to the current scope; * `<>`, which provides scoped ownership for a dynamically allocated array; * `<>`, a versatile tool for managing shared ownership of an object or array; * `<>`, a non-owning observer to a shared_ptr-managed object that can be promoted temporarily to shared_ptr; -* `<>`, a pointer to objects with an embedded reference count. +* `<>`, a pointer to objects with an embedded reference count; +* `<>`, providing shared ownership within a single thread. `shared_ptr` and `weak_ptr` are part of the {cpp} standard since its 2011 iteration. diff --git a/doc/smart_ptr/local_shared_ptr.adoc b/doc/smart_ptr/local_shared_ptr.adoc new file mode 100644 index 0000000..d7d34dd --- /dev/null +++ b/doc/smart_ptr/local_shared_ptr.adoc @@ -0,0 +1,719 @@ +//// +Copyright 2017 Peter Dimov + +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 +//// + +[#local_shared_ptr] +# local_shared_ptr: Shared Ownership within a Single Thread +:toc: +:toc-title: +:idprefix: local_shared_ptr_ + +## Description + +`local_shared_ptr` is nearly identical to `shared_ptr`, with the only difference of note being that its reference count is +updated with non-atomic operations. As such, a `local_shared_ptr` and all its copies must reside in (be local to) a single +thread (hence the name.) + +`local_shared_ptr` can be converted to `shared_ptr` and vice versa. Creating a `local_shared_ptr` from a `shared_ptr` creates +a new local reference count; this means that two `local_shared_ptr` instances, both created from the same `shared_ptr`, refer +to the same object but don't share the same count, and as such, can safely be used by two different threads. + +.Two local_shared_ptr instances created from a shared_ptr +``` +shared_ptr p1( new X ); + +local_shared_ptr p2( p1 ); // p2.local_use_count() == 1 +local_shared_ptr p3( p1 ); // p3.local_use_count() also 1 +``` + +Creating the second `local_shared_ptr` from the first one, however, does lead to the two sharing the same count: + +.A local_shared_ptr created from another local_shared_ptr +``` +shared_ptr p1( new X ); + +local_shared_ptr p2( p1 ); // p2.local_use_count() == 1 +local_shared_ptr p3( p2 ); // p3.local_use_count() == 2 +``` + +Two `shared_ptr` instances created from the same `local_shared_ptr` do share ownership: + +.Two shared_ptr instances created from a local_shared_ptr +``` +local_shared_ptr p1( new X ); + +shared_ptr p2( p1 ); // p2.use_count() == 2 +shared_ptr p3( p1 ); // p3.use_count() == 3 +``` + +Here `p2.use_count()` is 2, because `p1` holds a reference, too. + +One can think of `local_shared_ptr` as `shared_ptr>`, with the outer `shared_ptr` using non-atomic operations for +its count. Converting from `local_shared_ptr` to `shared_ptr` gives you a copy of the inner `shared_ptr`; converting from `shared_ptr` +wraps it into an outer `shared_ptr` with a non-atomic use count (conceptually speaking) and returns the result. + +## Synopsis + +`local_shared_ptr` is defined in ``. + +``` +namespace boost { + + template class local_shared_ptr { + public: + + typedef /*see below*/ element_type; + + // constructors + + constexpr local_shared_ptr() noexcept; + constexpr local_shared_ptr(std::nullptr_t) noexcept; + + template explicit local_shared_ptr(Y * p); + + template local_shared_ptr(Y * p, D d); + template local_shared_ptr(std::nullptr_t p, D d); + + template local_shared_ptr(Y * p, D d, A a); + template local_shared_ptr(std::nullptr_t p, D d, A a); + + local_shared_ptr(local_shared_ptr const & r) noexcept; + template local_shared_ptr(local_shared_ptr const & r) noexcept; + + local_shared_ptr(local_shared_ptr && r) noexcept; + template local_shared_ptr(local_shared_ptr && r) noexcept; + + template local_shared_ptr( shared_ptr const & r ); + template local_shared_ptr( shared_ptr && r ); + + template local_shared_ptr(local_shared_ptr const & r, element_type * p) noexcept; + template local_shared_ptr(local_shared_ptr && r, element_type * p) noexcept; + + template local_shared_ptr(std::unique_ptr && r); + + // destructor + + ~local_shared_ptr() noexcept; + + // assignment + + local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; + template local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; + + local_shared_ptr & operator=(local_shared_ptr const && r) noexcept; + template local_shared_ptr & operator=(local_shared_ptr const && r) noexcept; + + template local_shared_ptr & operator=(std::unique_ptr && r); + + local_shared_ptr & operator=(std::nullptr_t) noexcept; + + // reset + + void reset() noexcept; + + template void reset(Y * p); + template void reset(Y * p, D d); + template void reset(Y * p, D d, A a); + + template void reset(local_shared_ptr const & r, element_type * p) noexcept; + template void reset(local_shared_ptr && r, element_type * p) noexcept; + + // accessors + + T & operator*() const noexcept; // only valid when T is not an array type + T * operator->() const noexcept; // only valid when T is not an array type + + // only valid when T is an array type + element_type & operator[](std::ptrdiff_t i) const noexcept; + + element_type * get() const noexcept; + + long local_use_count() const noexcept; + + // conversions + + explicit operator bool() const noexcept; + + template operator shared_ptr() const noexcept; + template operator weak_ptr() const noexcept; + + // swap + + void swap(local_shared_ptr & b) noexcept; + + // owner_before + + template bool owner_before(local_shared_ptr const & rhs) const noexcept; + }; + + // comparisons + + template + bool operator==(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; + template + bool operator==(local_shared_ptr const & a, shared_ptr const & b) noexcept; + template + bool operator==(shared_ptr const & a, local_shared_ptr const & b) noexcept; + + template + bool operator!=(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; + template + bool operator!=(local_shared_ptr const & a, shared_ptr const & b) noexcept; + template + bool operator!=(shared_ptr const & a, local_shared_ptr const & b) noexcept; + + template bool operator==(local_shared_ptr const & p, std::nullptr_t) noexcept; + template bool operator==(std::nullptr_t, local_shared_ptr const & p) noexcept; + + template bool operator!=(local_shared_ptr const & p, std::nullptr_t) noexcept; + template bool operator!=(std::nullptr_t, local_shared_ptr const & p) noexcept; + + template + bool operator<(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; + + // swap + + template void swap(local_shared_ptr & a, local_shared_ptr & b) noexcept; + + // get_pointer + + template + typename local_shared_ptr::element_type * + get_pointer(local_shared_ptr const & p) noexcept; + + // casts + + template + local_shared_ptr static_pointer_cast(local_shared_ptr const & r) noexcept; + + template + local_shared_ptr const_pointer_cast(local_shared_ptr const & r) noexcept; + + template + local_shared_ptr dynamic_pointer_cast(local_shared_ptr const & r) noexcept; + + template + local_shared_ptr reinterpret_pointer_cast(local_shared_ptr const & r) noexcept; + + // stream I/O + + template + std::basic_ostream & + operator<< (std::basic_ostream & os, local_shared_ptr const & p); + + // get_deleter + + template D * get_deleter(local_shared_ptr const & p) noexcept; +} +``` + +## Members + +### element_type +``` +typedef ... element_type; +``` +`element_type` is `T` when `T` is not an array type, and `U` when `T` is `U[]` or `U[N]`. + +### default constructor +``` +constexpr local_shared_ptr() noexcept; +``` +``` +constexpr local_shared_ptr(std::nullptr_t) noexcept; +``` +[none] +* {blank} ++ +Effects:: Constructs an empty `local_shared_ptr`. +Postconditions:: `local_use_count() == 0 && get() == 0`. + +### pointer constructor +``` +template explicit local_shared_ptr(Y * p); +``` +[none] +* {blank} ++ +Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr( p )`. + +Postconditions:: `local_use_count() == 1 && get() == p`. + +Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. + +### constructors taking a deleter +``` +template local_shared_ptr(Y * p, D d); +``` +``` +template local_shared_ptr(std::nullptr_t p, D d); +``` +[none] +* {blank} ++ +Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr( p, d )`. + +Postconditions:: `local_use_count() == 1 && get() == p`. + +Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. + +``` +template local_shared_ptr(Y * p, D d, A a); +``` +``` +template local_shared_ptr(std::nullptr_t p, D d, A a); +``` +[none] +* {blank} ++ +Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr( p, d, a )`. + +Postconditions:: `local_use_count() == 1 && get() == p`. + +Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. + +### copy and converting constructors +``` +local_shared_ptr(local_shared_ptr const & r) noexcept; +``` +``` +template local_shared_ptr(local_shared_ptr const & r) noexcept; +``` +[none] +* {blank} ++ +Requires:: `Y*` should be convertible to `T*`. + +Effects:: If `r` is empty, constructs an empty `local_shared_ptr`; otherwise, constructs a `local_shared_ptr` that shares ownership with `r`. + +Postconditions:: `get() == r.get() && local_use_count() == r.local_use_count()`. + +### move constructors +``` +local_shared_ptr(local_shared_ptr && r) noexcept; +``` +``` +template local_shared_ptr(local_shared_ptr && r) noexcept; +``` +[none] +* {blank} ++ +Requires:: `Y*` should be convertible to `T*`. + +Effects:: Move-constructs a `local_shared_ptr` from `r`. + +Postconditions:: `*this` contains the old value of `r`. `r` is empty and `r.get() == 0`. + +### shared_ptr constructor +``` +template local_shared_ptr( shared_ptr const & r ); +``` +``` +template local_shared_ptr( shared_ptr && r ); +``` +[none] +* {blank} ++ +Effects:: Constructs a `local_shared_ptr` that owns `r`. + +Postconditions:: `local_use_count() == 1`. `get()` returns the old value of `r.get()`. + +Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. + +### aliasing constructor +``` +template local_shared_ptr(local_shared_ptr const & r, element_type * p) noexcept; +``` +[none] +* {blank} ++ +Effects:: constructs a `local_shared_ptr` that shares ownership with `r` and stores `p`. + +Postconditions:: `get() == p && local_use_count() == r.local_use_count()`. + +### aliasing move constructor +``` +template local_shared_ptr(local_shared_ptr && r, element_type * p) noexcept; +``` +[none] +* {blank} ++ +Effects:: Move-constructs a `local_shared_ptr` from `r`, while storing `p` instead. + +Postconditions:: `get() == p` and `local_use_count()` equals the old count of `r`. `r` is empty and `r.get() == 0`. + +### unique_ptr constructor +``` +template local_shared_ptr(std::unique_ptr && r); +``` +[none] +* {blank} ++ +Requires:: `Y*` should be convertible to `T*`. + +Effects:: +- When `r.get() == 0`, equivalent to `local_shared_ptr()`; +- Otherwise, constructs a `local_shared_ptr` that owns `shared_ptr( std::move(r) )`. + +Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. + +Exception safety:: If an exception is thrown, the constructor has no effect. + +### destructor +``` +~local_shared_ptr() noexcept; +``` +[none] +* {blank} ++ +Effects:: +- If `*this` is empty, or shares ownership with another `local_shared_ptr` instance (`local_use_count() > 1`), there are no side effects. +- Otherwise, destroys the owned `shared_ptr`. + +### assignment +``` +local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; +``` +``` +template local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(r).swap(*this)`. +Returns:: `*this`. + +``` +local_shared_ptr & operator=(local_shared_ptr && r) noexcept; +``` +``` +template local_shared_ptr & operator=(local_shared_ptr && r) noexcept; +``` +``` +template local_shared_ptr & operator=(std::unique_ptr && r); +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(std::move(r)).swap(*this)`. +Returns:: `*this`. + +``` +local_shared_ptr & operator=(std::nullptr_t) noexcept; +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr().swap(*this)`. +Returns:: `*this`. + +### reset +``` +void reset() noexcept; +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr().swap(*this)`. + +``` +template void reset(Y * p); +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(p).swap(*this)`. + +``` +template void reset(Y * p, D d); +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(p, d).swap(*this)`. + +``` +template void reset(Y * p, D d, A a); +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(p, d, a).swap(*this)`. + +``` +template void reset(local_shared_ptr const & r, element_type * p) noexcept; +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(r, p).swap(*this)`. + +``` +template void reset(local_shared_ptr && r, element_type * p) noexcept; +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(std::move(r), p).swap(*this)`. + +### indirection +``` +T & operator*() const noexcept; +``` +[none] +* {blank} ++ +Requires:: `T` should not be an array type. +Returns:: `*get()`. + +``` +T * operator->() const noexcept; +``` +[none] +* {blank} ++ +Requires:: `T` should not be an array type. +Returns:: `get()`. + +``` +element_type & operator[](std::ptrdiff_t i) const noexcept; +``` +[none] +* {blank} ++ +Requires:: `T` should be an array type. The stored pointer must not be 0. `i >= 0`. If `T` is `U[N]`, `i < N`. +Returns:: `get()[i]`. + +### get + +``` +element_type * get() const noexcept; +``` +[none] +* {blank} ++ +Returns:: The stored pointer. + +### local_use_count +``` +long local_use_count() const noexcept; +``` +[none] +* {blank} ++ +Returns:: The number of `local_shared_ptr` objects, `*this` included, that share ownership with `*this`, or 0 when `*this` is empty. + +### conversions +``` +explicit operator bool() const noexcept; +``` +[none] +* {blank} ++ +Returns:: `get() != 0`. + +NOTE: On C++03 compilers, the return value is of an unspecified type. + +``` +template operator shared_ptr() const noexcept; +``` +``` +template operator weak_ptr() const noexcept; +``` +[none] +* {blank} ++ +Requires:: `T*` should be convertible to `Y*`. +Returns:: a copy of the owned `shared_ptr`. + +### swap +``` +void swap(local_shared_ptr & b) noexcept; +``` +[none] +* {blank} ++ +Effects:: Exchanges the contents of the two smart pointers. + +### owner_before +``` +template bool owner_before(local_shared_ptr const & rhs) const noexcept; +``` +[none] +* {blank} ++ +Effects:: See the description of `operator<`. + +## Free Functions + +### comparison +``` +template + bool operator==(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; +``` +``` +template + bool operator==(local_shared_ptr const & a, shared_ptr const & b) noexcept; +``` +``` +template + bool operator==(shared_ptr const & a, local_shared_ptr const & b) noexcept; +``` +[none] +* {blank} ++ +Returns:: `a.get() == b.get()`. + +``` +template + bool operator!=(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; +``` +``` +template + bool operator!=(local_shared_ptr const & a, shared_ptr const & b) noexcept; +``` +``` +template + bool operator!=(shared_ptr const & a, local_shared_ptr const & b) noexcept; +``` +[none] +* {blank} ++ +Returns:: `a.get() != b.get()`. + +``` +template bool operator==(local_shared_ptr const & p, std::nullptr_t) noexcept; +``` +``` +template bool operator==(std::nullptr_t, local_shared_ptr const & p) noexcept; +``` +[none] +* {blank} ++ +Returns:: `p.get() == 0`. + +``` +template bool operator!=(local_shared_ptr const & p, std::nullptr_t) noexcept; +``` +``` +template bool operator!=(std::nullptr_t, local_shared_ptr const & p) noexcept; +``` +[none] +* {blank} ++ +Returns:: `p.get() != 0`. + +``` +template + bool operator<(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; +``` +[none] +* {blank} ++ +Returns:: An unspecified value such that + - `operator<` is a strict weak ordering as described in section [lib.alg.sorting] of the {cpp} standard; + - under the equivalence relation defined by `operator<`, `!(a < b) && !(b < a)`, two `local_shared_ptr` instances + are equivalent if and only if they share ownership or are both empty. + +NOTE: Allows `local_shared_ptr` objects to be used as keys in associative containers. + +NOTE: The rest of the comparison operators are omitted by design. + +### swap +``` +template void swap(local_shared_ptr & a, local_shared_ptr & b) noexcept; +``` +[none] +* {blank} ++ +Effects:: Equivalent to `a.swap(b)`. + +### get_pointer +``` +template + typename local_shared_ptr::element_type * + get_pointer(local_shared_ptr const & p) noexcept; +``` +[none] +* {blank} ++ +Returns:: `p.get()`. + +NOTE: Provided as an aid to generic programming. Used by `mem_fn`. + +### static_pointer_cast +``` +template + local_shared_ptr static_pointer_cast(local_shared_ptr const & r) noexcept; +``` +[none] +* {blank} ++ +Requires:: The expression `static_cast( (U*)0 )` must be well-formed. +Returns:: `local_shared_ptr( r, static_cast::element_type*>(r.get()) )`. + +CAUTION: The seemingly equivalent expression `local_shared_ptr(static_cast(r.get()))` will eventually +result in undefined behavior, attempting to delete the same object twice. + +### const_pointer_cast +``` +template + local_shared_ptr const_pointer_cast(local_shared_ptr const & r) noexcept; +``` +[none] +* {blank} ++ +Requires:: The expression `const_cast( (U*)0 )` must be well-formed. +Returns:: `local_shared_ptr( r, const_cast::element_type*>(r.get()) )`. + +### dynamic_pointer_cast +``` +template + local_shared_ptr dynamic_pointer_cast(local_shared_ptr const & r) noexcept; +``` +[none] +* {blank} ++ +Requires:: The expression `dynamic_cast( (U*)0 )` must be well-formed. +Returns:: + - When `dynamic_cast::element_type*>(r.get())` returns a nonzero value `p`, `local_shared_ptr(r, p)`; + - Otherwise, `local_shared_ptr()`. + +### reinterpret_pointer_cast +``` +template + local_shared_ptr reinterpret_pointer_cast(local_shared_ptr const & r) noexcept; +``` +[none] +* {blank} ++ +Requires:: The expression `reinterpret_cast( (U*)0 )` must be well-formed. +Returns:: `local_shared_ptr( r, reinterpret_cast::element_type*>(r.get()) )`. + +### operator<< +``` +template + std::basic_ostream & + operator<< (std::basic_ostream & os, local_shared_ptr const & p); +``` +[none] +* {blank} ++ +Effects:: `os << p.get();`. +Returns:: `os`. + +### get_deleter +``` +template + D * get_deleter(local_shared_ptr const & p) noexcept; +``` +[none] +* {blank} ++ +Returns:: If `*this` owns a `shared_ptr` instance `p`, `get_deleter( p )`, otherwise 0. + diff --git a/include/boost/smart_ptr/allocate_shared_array.hpp b/include/boost/smart_ptr/allocate_shared_array.hpp index 56bed2f..5857c47 100644 --- a/include/boost/smart_ptr/allocate_shared_array.hpp +++ b/include/boost/smart_ptr/allocate_shared_array.hpp @@ -767,6 +767,10 @@ public: &reinterpret_cast(deleter_) : 0; } + void* get_local_deleter(const sp_typeinfo&) { + return 0; + } + void* get_untyped_deleter() { return &reinterpret_cast(deleter_); } @@ -809,6 +813,10 @@ public: &reinterpret_cast(deleter_) : 0; } + void* get_local_deleter(const sp_typeinfo&) { + return 0; + } + void* get_untyped_deleter() { return &reinterpret_cast(deleter_); } @@ -856,6 +864,10 @@ public: &reinterpret_cast(deleter_) : 0; } + void* get_local_deleter(const sp_typeinfo&) { + return 0; + } + void* get_untyped_deleter() { return &reinterpret_cast(deleter_); } @@ -902,6 +914,10 @@ public: &reinterpret_cast(deleter_) : 0; } + void* get_local_deleter(const sp_typeinfo&) { + return 0; + } + void* get_untyped_deleter() { return &reinterpret_cast(deleter_); } diff --git a/include/boost/smart_ptr/detail/local_counted_base.hpp b/include/boost/smart_ptr/detail/local_counted_base.hpp index df652b3..2e5f6ae 100644 --- a/include/boost/smart_ptr/detail/local_counted_base.hpp +++ b/include/boost/smart_ptr/detail/local_counted_base.hpp @@ -17,7 +17,7 @@ // // See http://www.boost.org/libs/smart_ptr/ for documentation. -#include +#include #include #include #include @@ -55,9 +55,9 @@ public: { } - virtual void destroy() BOOST_SP_NOEXCEPT = 0; + virtual void local_cb_destroy() BOOST_SP_NOEXCEPT = 0; - virtual boost::shared_ptr get_shared_ptr() const BOOST_SP_NOEXCEPT = 0; + virtual boost::detail::shared_count local_cb_get_shared_count() const BOOST_SP_NOEXCEPT = 0; void add_ref() BOOST_SP_NOEXCEPT { @@ -78,7 +78,7 @@ public: if( local_use_count_ == 0 ) { - destroy(); + local_cb_destroy(); } } @@ -96,30 +96,30 @@ private: private: - boost::shared_ptr pn_; + shared_count pn_; public: - template explicit local_counted_impl( boost::shared_ptr const& pn ): pn_( pn ) + explicit local_counted_impl( shared_count const& pn ): pn_( pn ) { } #if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) - template explicit local_counted_impl( boost::shared_ptr&& pn ): pn_( std::move(pn) ) + explicit local_counted_impl( shared_count && pn ): pn_( std::move(pn) ) { } #endif - virtual void destroy() BOOST_SP_NOEXCEPT + virtual void local_cb_destroy() BOOST_SP_NOEXCEPT { delete this; } - virtual boost::shared_ptr get_shared_ptr() const BOOST_SP_NOEXCEPT + virtual boost::detail::shared_count local_cb_get_shared_count() const BOOST_SP_NOEXCEPT { - return const_pointer_cast( pn_ ); + return pn_; } }; @@ -127,16 +127,16 @@ class local_counted_impl_em: public local_counted_base { public: - boost::shared_ptr pn_; + shared_count pn_; - virtual void destroy() BOOST_SP_NOEXCEPT + virtual void local_cb_destroy() BOOST_SP_NOEXCEPT { - pn_.reset(); + shared_count().swap( pn_ ); } - virtual boost::shared_ptr get_shared_ptr() const BOOST_SP_NOEXCEPT + virtual boost::detail::shared_count local_cb_get_shared_count() const BOOST_SP_NOEXCEPT { - return const_pointer_cast( pn_ ); + return pn_; } }; diff --git a/include/boost/smart_ptr/detail/local_sp_deleter.hpp b/include/boost/smart_ptr/detail/local_sp_deleter.hpp new file mode 100644 index 0000000..7d04f1d --- /dev/null +++ b/include/boost/smart_ptr/detail/local_sp_deleter.hpp @@ -0,0 +1,91 @@ +#ifndef BOOST_SMART_PTR_DETAIL_LOCAL_SP_DELETER_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_LOCAL_SP_DELETER_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// detail/local_sp_deleter.hpp +// +// Copyright 2017 Peter Dimov +// +// 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/smart_ptr/ for documentation. + +#include +#include + +namespace boost +{ + +namespace detail +{ + +template class local_sp_deleter: public local_counted_impl_em +{ +private: + + D d_; + +public: + + local_sp_deleter(): d_() + { + } + + explicit local_sp_deleter( D const& d ) BOOST_SP_NOEXCEPT: d_( d ) + { + } + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + explicit local_sp_deleter( D&& d ) BOOST_SP_NOEXCEPT: d_( std::move(d) ) + { + } + +#endif + + D& deleter() + { + return d_; + } + + template void operator()( Y* p ) BOOST_SP_NOEXCEPT + { + d_( p ); + } + +#if !defined( BOOST_NO_CXX11_NULLPTR ) + + void operator()( boost::detail::sp_nullptr_t p ) BOOST_SP_NOEXCEPT + { + d_( p ); + } + +#endif +}; + +template<> class local_sp_deleter +{ +}; + +template D * get_local_deleter( local_sp_deleter * p ) +{ + return &p->deleter(); +} + +inline void * get_local_deleter( local_sp_deleter * /*p*/ ) +{ + return 0; +} + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_LOCAL_SP_DELETER_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/shared_count.hpp b/include/boost/smart_ptr/detail/shared_count.hpp index 7f375e8..1fc1433 100644 --- a/include/boost/smart_ptr/detail/shared_count.hpp +++ b/include/boost/smart_ptr/detail/shared_count.hpp @@ -496,6 +496,11 @@ public: return pi_? pi_->get_deleter( ti ): 0; } + void * get_local_deleter( sp_typeinfo const & ti ) const + { + return pi_? pi_->get_local_deleter( ti ): 0; + } + void * get_untyped_deleter() const { return pi_? pi_->get_untyped_deleter(): 0; diff --git a/include/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp b/include/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp index cebc243..ec6f6ee 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp @@ -104,6 +104,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_aix.hpp b/include/boost/smart_ptr/detail/sp_counted_base_aix.hpp index fe6c727..ce8ee68 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_aix.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_aix.hpp @@ -96,6 +96,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp b/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp index 7598495..8b3bfad 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp @@ -98,6 +98,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp b/include/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp index 6c268e8..065f7c3 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp @@ -124,6 +124,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_cw_x86.hpp b/include/boost/smart_ptr/detail/sp_counted_base_cw_x86.hpp index 81eba6f..3a3d4d4 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_cw_x86.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_cw_x86.hpp @@ -112,6 +112,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp index f6e3904..6c3cce8 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp @@ -111,6 +111,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp index 545c8ae..76ac2a6 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp @@ -135,6 +135,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp index 2e5bc0e..0fb8074 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp @@ -135,6 +135,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp index c6d20ce..b8bb707 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp @@ -120,6 +120,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp index 173dce5..3d2dd61 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp @@ -127,6 +127,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_nt.hpp b/include/boost/smart_ptr/detail/sp_counted_base_nt.hpp index 5c901f9..dea905c 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_nt.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_nt.hpp @@ -59,6 +59,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_pt.hpp b/include/boost/smart_ptr/detail/sp_counted_base_pt.hpp index a16d2d8..85f2563 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_pt.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_pt.hpp @@ -71,6 +71,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_snc_ps3.hpp b/include/boost/smart_ptr/detail/sp_counted_base_snc_ps3.hpp index 56ed79f..7b5f917 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_snc_ps3.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_snc_ps3.hpp @@ -115,6 +115,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_solaris.hpp b/include/boost/smart_ptr/detail/sp_counted_base_solaris.hpp index 0e05fef..0db9c6c 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_solaris.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_solaris.hpp @@ -62,6 +62,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_spin.hpp b/include/boost/smart_ptr/detail/sp_counted_base_spin.hpp index 77734e7..faf503a 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_spin.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_spin.hpp @@ -84,6 +84,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp b/include/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp index cab8453..7a188f8 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp @@ -90,6 +90,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_sync.hpp b/include/boost/smart_ptr/detail/sp_counted_base_sync.hpp index fafed0e..d2138e7 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_sync.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_sync.hpp @@ -109,6 +109,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_vacpp_ppc.hpp b/include/boost/smart_ptr/detail/sp_counted_base_vacpp_ppc.hpp index 162f309..f2de3b0 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_vacpp_ppc.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_vacpp_ppc.hpp @@ -104,6 +104,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_w32.hpp b/include/boost/smart_ptr/detail/sp_counted_base_w32.hpp index 4ba509c..960e42e 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_w32.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_w32.hpp @@ -67,6 +67,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/smart_ptr/detail/sp_counted_impl.hpp index b29769e..fa2f75e 100644 --- a/include/boost/smart_ptr/detail/sp_counted_impl.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_impl.hpp @@ -26,6 +26,7 @@ #include #include +#include #if defined(BOOST_SP_USE_QUICK_ALLOCATOR) #include @@ -50,6 +51,19 @@ void sp_scalar_destructor_hook( void * px, std::size_t size, void * pn ); namespace detail { +// get_local_deleter + +template class local_sp_deleter; + +template D * get_local_deleter( D * /*p*/ ) +{ + return 0; +} + +template D * get_local_deleter( local_sp_deleter * p ); + +// + template class sp_counted_impl_p: public sp_counted_base { private: @@ -83,6 +97,11 @@ public: return 0; } + virtual void * get_local_deleter( sp_typeinfo const & ) + { + return 0; + } + virtual void * get_untyped_deleter() { return 0; @@ -158,6 +177,11 @@ public: return ti == BOOST_SP_TYPEID(D)? &reinterpret_cast( del ): 0; } + virtual void * get_local_deleter( sp_typeinfo const & ti ) + { + return ti == BOOST_SP_TYPEID(D)? boost::detail::get_local_deleter( boost::addressof( del ) ): 0; + } + virtual void * get_untyped_deleter() { return &reinterpret_cast( del ); @@ -246,6 +270,11 @@ public: return ti == BOOST_SP_TYPEID( D )? &reinterpret_cast( d_ ): 0; } + virtual void * get_local_deleter( sp_typeinfo const & ti ) + { + return ti == BOOST_SP_TYPEID(D)? boost::detail::get_local_deleter( boost::addressof( d_ ) ): 0; + } + virtual void * get_untyped_deleter() { return &reinterpret_cast( d_ ); diff --git a/include/boost/smart_ptr/local_shared_ptr.hpp b/include/boost/smart_ptr/local_shared_ptr.hpp index d0e1721..2e3b8bf 100644 --- a/include/boost/smart_ptr/local_shared_ptr.hpp +++ b/include/boost/smart_ptr/local_shared_ptr.hpp @@ -11,7 +11,6 @@ // // See http://www.boost.org/libs/smart_ptr/ for documentation. -#include #include namespace boost @@ -22,46 +21,7 @@ template class local_shared_ptr; namespace detail { -template class local_sp_deleter: public local_counted_impl_em -{ -private: - - D d_; - -public: - - local_sp_deleter(): d_() - { - } - - explicit local_sp_deleter( D const& d ) BOOST_SP_NOEXCEPT: d_( d ) - { - } - -#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) - - explicit local_sp_deleter( D&& d ) BOOST_SP_NOEXCEPT: d_( std::move(d) ) - { - } - -#endif - - template void operator()( Y* p ) const BOOST_SP_NOEXCEPT - { - d_( p ); - } - -#if !defined( BOOST_NO_CXX11_NULLPTR ) - - void operator()( boost::detail::sp_nullptr_t p ) const BOOST_SP_NOEXCEPT - { - d_( p ); - } - -#endif -}; - -template< class E, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E > * ppx, Y * p, boost::detail::local_counted_base * & pn ) +template< class E, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E > * /*ppx*/, Y * p, boost::detail::local_counted_base * & pn ) { boost::detail::sp_assert_convertible< Y, E >(); @@ -71,12 +31,12 @@ template< class E, class Y > inline void lsp_pointer_construct( boost::local_sha D * pd = static_cast< D * >( p2._internal_get_untyped_deleter() ); - pd->pn_ = p2; + pd->pn_ = p2._internal_count(); pn = pd; } -template< class E, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E[] > * ppx, Y * p, boost::detail::local_counted_base * & pn ) +template< class E, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E[] > * /*ppx*/, Y * p, boost::detail::local_counted_base * & pn ) { boost::detail::sp_assert_convertible< Y[], E[] >(); @@ -86,12 +46,12 @@ template< class E, class Y > inline void lsp_pointer_construct( boost::local_sha D * pd = static_cast< D * >( p2._internal_get_untyped_deleter() ); - pd->pn_ = p2; + pd->pn_ = p2._internal_count(); pn = pd; } -template< class E, std::size_t N, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E[N] > * ppx, Y * p, boost::detail::local_counted_base * & pn ) +template< class E, std::size_t N, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E[N] > * /*ppx*/, Y * p, boost::detail::local_counted_base * & pn ) { boost::detail::sp_assert_convertible< Y[N], E[N] >(); @@ -101,12 +61,12 @@ template< class E, std::size_t N, class Y > inline void lsp_pointer_construct( b D * pd = static_cast< D * >( p2._internal_get_untyped_deleter() ); - pd->pn_ = p2; + pd->pn_ = p2._internal_count(); pn = pd; } -template< class E, class P, class D > inline void lsp_deleter_construct( boost::local_shared_ptr< E > * ppx, P p, D const& d, boost::detail::local_counted_base * & pn ) +template< class E, class P, class D > inline void lsp_deleter_construct( boost::local_shared_ptr< E > * /*ppx*/, P p, D const& d, boost::detail::local_counted_base * & pn ) { typedef boost::detail::local_sp_deleter D2; @@ -114,12 +74,12 @@ template< class E, class P, class D > inline void lsp_deleter_construct( boost:: D2 * pd = static_cast< D2 * >( p2._internal_get_untyped_deleter() ); - pd->pn_ = p2; + pd->pn_ = p2._internal_count(); pn = pd; } -template< class E, class P, class D, class A > inline void lsp_allocator_construct( boost::local_shared_ptr< E > * ppx, P p, D const& d, A const& a, boost::detail::local_counted_base * & pn ) +template< class E, class P, class D, class A > inline void lsp_allocator_construct( boost::local_shared_ptr< E > * /*ppx*/, P p, D const& d, A const& a, boost::detail::local_counted_base * & pn ) { typedef boost::detail::local_sp_deleter D2; @@ -127,11 +87,15 @@ template< class E, class P, class D, class A > inline void lsp_allocator_constru D2 * pd = static_cast< D2 * >( p2._internal_get_untyped_deleter() ); - pd->pn_ = p2; + pd->pn_ = p2._internal_count(); pn = pd; } +struct lsp_internal_constructor_tag +{ +}; + } // namespace detail // @@ -184,6 +148,11 @@ public: #endif + // internal constructor, used by make_shared + BOOST_CONSTEXPR local_shared_ptr( boost::detail::lsp_internal_constructor_tag, T * px_, boost::detail::local_counted_base * pn_ ) BOOST_SP_NOEXCEPT : px( px_ ), pn( pn_ ) + { + } + template explicit local_shared_ptr( Y * p ): px( p ), pn( 0 ) { @@ -228,7 +197,7 @@ public: if( r.use_count() != 0 ) { - pn = new boost::detail::local_counted_impl( r ); + pn = new boost::detail::local_counted_impl( r._internal_count() ); } } @@ -242,7 +211,8 @@ public: if( r.use_count() != 0 ) { - pn = new boost::detail::local_counted_impl( std::move(r) ); + pn = new boost::detail::local_counted_impl( r._internal_count() ); + r.reset(); } } @@ -261,7 +231,7 @@ public: if( px ) { - pn = new boost::detail::local_counted_impl( shared_ptr( std::move(r) ) ); + pn = new boost::detail::local_counted_impl( shared_ptr( std::move(r) )._internal_count() ); } } @@ -484,7 +454,7 @@ public: if( pn ) { - return static_pointer_cast( pn->get_shared_ptr() ); + return shared_ptr( boost::detail::sp_internal_constructor_tag(), px, pn->local_cb_get_shared_count() ); } else { @@ -502,7 +472,7 @@ public: if( pn ) { - return static_pointer_cast( pn->get_shared_ptr() ); + return shared_ptr( boost::detail::sp_internal_constructor_tag(), px, pn->local_cb_get_shared_count() ); } else { @@ -693,6 +663,13 @@ template std::basic_ostream & operator<< ( std: #endif // !defined(BOOST_NO_IOSTREAM) +// get_deleter + +template D * get_deleter( local_shared_ptr const & p ) BOOST_SP_NOEXCEPT +{ + return get_deleter( shared_ptr( p ) ); +} + // hash_value template< class T > struct hash; diff --git a/include/boost/smart_ptr/make_local_shared.hpp b/include/boost/smart_ptr/make_local_shared.hpp new file mode 100644 index 0000000..23114fe --- /dev/null +++ b/include/boost/smart_ptr/make_local_shared.hpp @@ -0,0 +1,17 @@ +#ifndef BOOST_SMART_PTR_MAKE_LOCAL_SHARED_HPP_INCLUDED +#define BOOST_SMART_PTR_MAKE_LOCAL_SHARED_HPP_INCLUDED + +// make_local_shared.hpp +// +// Copyright 2017 Peter Dimov +// +// 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/smart_ptr/ for documentation. + +#include +#include + +#endif // #ifndef BOOST_SMART_PTR_MAKE_LOCAL_SHARED_HPP_INCLUDED diff --git a/include/boost/smart_ptr/make_local_shared_array.hpp b/include/boost/smart_ptr/make_local_shared_array.hpp new file mode 100644 index 0000000..136c767 --- /dev/null +++ b/include/boost/smart_ptr/make_local_shared_array.hpp @@ -0,0 +1,63 @@ +#ifndef BOOST_SMART_PTR_MAKE_LOCAL_SHARED_ARRAY_HPP_INCLUDED +#define BOOST_SMART_PTR_MAKE_LOCAL_SHARED_ARRAY_HPP_INCLUDED + +// make_local_shared_array.hpp +// +// Copyright 2017 Peter Dimov +// +// 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/smart_ptr/ for documentation. + +#include +#include +#include +#include + +namespace boost +{ + +namespace detail +{ + +template struct lsp_if_array +{ +}; + +template struct lsp_if_array +{ + typedef boost::local_shared_ptr type; +}; + +template struct lsp_if_array +{ + typedef boost::local_shared_ptr type; +}; + +} // namespace detail + +template typename boost::detail::lsp_if_array::type make_local_shared( Args&&... args ) +{ + return boost::make_shared( std::forward(args)... ); +} + +template typename boost::detail::lsp_if_array::type make_local_shared_noinit( Args&&... args ) +{ + return boost::make_shared_noinit( std::forward(args)... ); +} + +template typename boost::detail::lsp_if_array::type allocate_local_shared( A const & a, Args&&... args ) +{ + return boost::allocate_shared( a, std::forward(args)... ); +} + +template typename boost::detail::lsp_if_array::type allocate_local_shared_noinit( A const & a, Args&&... args ) +{ + return boost::allocate_shared_noinit( a, std::forward(args)... ); +} + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_MAKE_SHARED_OBJECT_HPP_INCLUDED diff --git a/include/boost/smart_ptr/make_local_shared_object.hpp b/include/boost/smart_ptr/make_local_shared_object.hpp new file mode 100644 index 0000000..518c24d --- /dev/null +++ b/include/boost/smart_ptr/make_local_shared_object.hpp @@ -0,0 +1,199 @@ +#ifndef BOOST_SMART_PTR_MAKE_LOCAL_SHARED_OBJECT_HPP_INCLUDED +#define BOOST_SMART_PTR_MAKE_LOCAL_SHARED_OBJECT_HPP_INCLUDED + +// make_local_shared_object.hpp +// +// Copyright 2017 Peter Dimov +// +// 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/smart_ptr/ for documentation. + +#include +#include +#include +#include +#include + +namespace boost +{ + +namespace detail +{ + +// lsp_if_not_array + +template struct lsp_if_not_array +{ + typedef boost::local_shared_ptr type; +}; + +template struct lsp_if_not_array +{ +}; + +template struct lsp_if_not_array +{ +}; + +// lsp_ms_deleter + +template class lsp_ms_deleter: public local_counted_impl_em +{ +private: + + typedef typename sp_aligned_storage::value>::type storage_type; + + storage_type storage_; + A a_; + bool initialized_; + +private: + + void destroy() BOOST_SP_NOEXCEPT + { + if( initialized_ ) + { + T * p = reinterpret_cast< T* >( storage_.data_ ); + +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + std::allocator_traits::destroy( a_, p ); + +#else + + p->~T(); + +#endif + + initialized_ = false; + } + } + +public: + + explicit lsp_ms_deleter( A const & a ) BOOST_SP_NOEXCEPT : a_( a ), initialized_( false ) + { + } + + // optimization: do not copy storage_ + lsp_ms_deleter( lsp_ms_deleter const & r ) BOOST_SP_NOEXCEPT : a_( r.a_), initialized_( false ) + { + } + + ~lsp_ms_deleter() BOOST_SP_NOEXCEPT + { + destroy(); + } + + void operator()( T * ) BOOST_SP_NOEXCEPT + { + destroy(); + } + + static void operator_fn( T* ) BOOST_SP_NOEXCEPT // operator() can't be static + { + } + + void * address() BOOST_SP_NOEXCEPT + { + return storage_.data_; + } + + void set_initialized() BOOST_SP_NOEXCEPT + { + initialized_ = true; + } +}; + +} // namespace detail + +template typename boost::detail::lsp_if_not_array::type allocate_local_shared( A const & a, Args&&... args ) +{ +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + typedef typename std::allocator_traits::template rebind_alloc A2; + +#else + + typedef typename A::template rebind::other A2; + +#endif + + A2 a2( a ); + + typedef boost::detail::lsp_ms_deleter D; + + boost::shared_ptr pt( static_cast< T* >( 0 ), boost::detail::sp_inplace_tag(), a2 ); + + D * pd = static_cast< D* >( pt._internal_get_untyped_deleter() ); + void * pv = pd->address(); + +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + std::allocator_traits::construct( a2, static_cast< T* >( pv ), std::forward( args )... ); + +#else + + ::new( pv ) T( std::forward( args )... ); + +#endif + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + + pd->pn_ = pt._internal_count(); + + return boost::local_shared_ptr( boost::detail::lsp_internal_constructor_tag(), pt2, pd ); +} + +template typename boost::detail::lsp_if_not_array::type allocate_local_shared_noinit( A const & a ) +{ +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + typedef typename std::allocator_traits::template rebind_alloc A2; + +#else + + typedef typename A::template rebind::other A2; + +#endif + + A2 a2( a ); + + typedef boost::detail::lsp_ms_deleter D; + + boost::shared_ptr pt( static_cast< T* >( 0 ), boost::detail::sp_inplace_tag(), a2 ); + + D * pd = static_cast< D* >( pt._internal_get_untyped_deleter() ); + void * pv = pd->address(); + + ::new( pv ) T; + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + + pd->pn_ = pt._internal_count(); + + return boost::local_shared_ptr( boost::detail::lsp_internal_constructor_tag(), pt2, pd ); +} + +template typename boost::detail::lsp_if_not_array::type make_local_shared( Args&&... args ) +{ + return boost::allocate_local_shared( std::allocator(), std::forward(args)... ); +} + +template typename boost::detail::lsp_if_not_array::type make_local_shared_noinit() +{ + return boost::allocate_shared_noinit( std::allocator() ); +} + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_MAKE_SHARED_OBJECT_HPP_INCLUDED diff --git a/include/boost/smart_ptr/shared_ptr.hpp b/include/boost/smart_ptr/shared_ptr.hpp index c87901a..e8a302c 100644 --- a/include/boost/smart_ptr/shared_ptr.hpp +++ b/include/boost/smart_ptr/shared_ptr.hpp @@ -323,6 +323,10 @@ template< class T, std::size_t N, class Y > inline void sp_deleter_construct( bo #endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) +struct sp_internal_constructor_tag +{ +}; + } // namespace detail @@ -355,6 +359,18 @@ public: { } +#endif + + BOOST_CONSTEXPR shared_ptr( boost::detail::sp_internal_constructor_tag, element_type * px_, boost::detail::shared_count const & pn_ ) BOOST_SP_NOEXCEPT : px( px_ ), pn( pn_ ) + { + } + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + BOOST_CONSTEXPR shared_ptr( boost::detail::sp_internal_constructor_tag, element_type * px_, boost::detail::shared_count && pn_ ) BOOST_SP_NOEXCEPT : px( px_ ), pn( std::move( pn_ ) ) + { + } + #endif template @@ -766,6 +782,11 @@ public: return pn.get_deleter( ti ); } + void * _internal_get_local_deleter( boost::detail::sp_typeinfo const & ti ) const BOOST_SP_NOEXCEPT + { + return pn.get_local_deleter( ti ); + } + void * _internal_get_untyped_deleter() const BOOST_SP_NOEXCEPT { return pn.get_untyped_deleter(); @@ -776,6 +797,11 @@ public: return px == r.px && pn == r.pn; } + boost::detail::shared_count _internal_count() const BOOST_NOEXCEPT + { + return pn; + } + // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. (Matthew Langston) @@ -980,27 +1006,13 @@ template std::basic_ostream & operator<< (std:: namespace detail { -#if ( defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3) ) || \ - ( defined(__EDG_VERSION__) && BOOST_WORKAROUND(__EDG_VERSION__, <= 238) ) || \ - ( defined(__HP_aCC) && BOOST_WORKAROUND(__HP_aCC, <= 33500) ) - -// g++ 2.9x doesn't allow static_cast(void *) -// apparently EDG 2.38 and HP aCC A.03.35 also don't accept it - -template D * basic_get_deleter(shared_ptr const & p) -{ - void const * q = p._internal_get_deleter(BOOST_SP_TYPEID(D)); - return const_cast(static_cast(q)); -} - -#else - template D * basic_get_deleter( shared_ptr const & p ) BOOST_SP_NOEXCEPT { return static_cast( p._internal_get_deleter(BOOST_SP_TYPEID(D)) ); } -#endif +template D * basic_get_local_deleter( D *, shared_ptr const & p ) BOOST_SP_NOEXCEPT; +template D const * basic_get_local_deleter( D const *, shared_ptr const & p ) BOOST_SP_NOEXCEPT; class esft2_deleter_wrapper { @@ -1035,17 +1047,22 @@ public: template D * get_deleter( shared_ptr const & p ) BOOST_SP_NOEXCEPT { - D *del = boost::detail::basic_get_deleter(p); + D * d = boost::detail::basic_get_deleter( p ); - if(del == 0) + if( d == 0 ) + { + d = boost::detail::basic_get_local_deleter( d, p ); + } + + if( d == 0 ) { boost::detail::esft2_deleter_wrapper *del_wrapper = boost::detail::basic_get_deleter(p); // The following get_deleter method call is fully qualified because // older versions of gcc (2.95, 3.2.3) fail to compile it when written del_wrapper->get_deleter() - if(del_wrapper) del = del_wrapper->::boost::detail::esft2_deleter_wrapper::get_deleter(); + if(del_wrapper) d = del_wrapper->::boost::detail::esft2_deleter_wrapper::get_deleter(); } - return del; + return d; } // atomic access @@ -1138,6 +1155,28 @@ template< class T > std::size_t hash_value( boost::shared_ptr const & p ) BOO } // namespace boost +#include + +namespace boost +{ + +namespace detail +{ + +template D * basic_get_local_deleter( D *, shared_ptr const & p ) BOOST_SP_NOEXCEPT +{ + return static_cast( p._internal_get_local_deleter( BOOST_SP_TYPEID(local_sp_deleter) ) ); +} + +template D const * basic_get_local_deleter( D const *, shared_ptr const & p ) BOOST_SP_NOEXCEPT +{ + return static_cast( p._internal_get_local_deleter( BOOST_SP_TYPEID(local_sp_deleter) ) ); +} + +} // namespace detail + +} // namespace boost + #if defined( BOOST_SP_DISABLE_DEPRECATED ) #pragma GCC diagnostic pop #endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 010fea3..134642d 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -230,5 +230,18 @@ import testing ; [ run lsp_array_n_test.cpp ] [ run lsp_array_cv_test.cpp ] [ run lsp_array_cast_test.cpp ] + + [ run get_local_deleter_test.cpp ] + [ run get_local_deleter_test2.cpp ] + [ run get_local_deleter_test3.cpp ] + [ run get_local_deleter_array_test.cpp ] + [ run get_local_deleter_array_test2.cpp ] + + [ run make_local_shared_test.cpp ] + [ run make_local_shared_esft_test.cpp ] + [ run allocate_local_shared_test.cpp ] + [ run allocate_local_shared_esft_test.cpp ] + + [ run local_sp_fn_test.cpp ] ; } diff --git a/test/allocate_local_shared_esft_test.cpp b/test/allocate_local_shared_esft_test.cpp new file mode 100644 index 0000000..65349c5 --- /dev/null +++ b/test/allocate_local_shared_esft_test.cpp @@ -0,0 +1,298 @@ +// allocate_local_shared_esft_test.cpp +// +// Copyright 2007-2009, 2017 Peter Dimov +// +// 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 + +#include + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) || defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) + +int main() +{ +} + +#else + +#include +#include +#include +#include +#include + +class X: public boost::enable_shared_from_this +{ +private: + + X( X const & ); + X & operator=( X const & ); + +public: + + static int instances; + + explicit X( int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0 ) + { + ++instances; + } + + ~X() + { + --instances; + } +}; + +int X::instances = 0; + +int main() +{ + BOOST_TEST_EQ( X::instances, 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator() ); + BOOST_TEST_EQ( X::instances, 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST_EQ( px, qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST_EQ( X::instances, 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared_noinit< X >( std::allocator() ); + BOOST_TEST_EQ( X::instances, 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST_EQ( px, qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST_EQ( X::instances, 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1 ); + BOOST_TEST_EQ( X::instances, 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST_EQ( px, qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST_EQ( X::instances, 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2 ); + BOOST_TEST_EQ( X::instances, 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST_EQ( px, qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST_EQ( X::instances, 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3 ); + BOOST_TEST_EQ( X::instances, 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST_EQ( px, qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST_EQ( X::instances, 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4 ); + BOOST_TEST_EQ( X::instances, 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST_EQ( px, qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST_EQ( X::instances, 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5 ); + BOOST_TEST_EQ( X::instances, 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST_EQ( px, qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST_EQ( X::instances, 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6 ); + BOOST_TEST_EQ( X::instances, 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST_EQ( px, qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST_EQ( X::instances, 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7 ); + BOOST_TEST_EQ( X::instances, 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST_EQ( px, qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST_EQ( X::instances, 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8 ); + BOOST_TEST_EQ( X::instances, 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST_EQ( px, qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST_EQ( X::instances, 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8, 9 ); + BOOST_TEST_EQ( X::instances, 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST_EQ( px, qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST_EQ( X::instances, 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST_EQ( X::instances, 0 ); + + return boost::report_errors(); +} + +#endif diff --git a/test/allocate_local_shared_test.cpp b/test/allocate_local_shared_test.cpp new file mode 100644 index 0000000..fa53dc0 --- /dev/null +++ b/test/allocate_local_shared_test.cpp @@ -0,0 +1,235 @@ +// allocate_local_shared_test.cpp +// +// Copyright 2007-2009, 2017 Peter Dimov +// +// 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 + +#include + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) || defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) + +int main() +{ +} + +#else + +#include +#include +#include +#include +#include + +class X +{ +private: + + X( X const & ); + X & operator=( X const & ); + + void * operator new( std::size_t n ) + { + // lack of this definition causes link errors on Comeau C++ + BOOST_ERROR( "private X::new called" ); + return ::operator new( n ); + } + + void operator delete( void * p ) + { + // lack of this definition causes link errors on MSVC + BOOST_ERROR( "private X::delete called" ); + ::operator delete( p ); + } + +public: + + static int instances; + + int v; + + explicit X( int a1 = 0, int a2 = 0, int a3 = 0, int a4 = 0, int a5 = 0, int a6 = 0, int a7 = 0, int a8 = 0, int a9 = 0 ): v( a1+a2+a3+a4+a5+a6+a7+a8+a9 ) + { + ++instances; + } + + ~X() + { + --instances; + } +}; + +int X::instances = 0; + +int main() +{ + { + boost::local_shared_ptr< int > pi = boost::allocate_local_shared< int >( std::allocator() ); + + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( *pi == 0 ); + } + + { + boost::local_shared_ptr< int > pi = boost::allocate_local_shared_noinit< int >( std::allocator() ); + + BOOST_TEST( pi.get() != 0 ); + } + + { + boost::local_shared_ptr< int > pi = boost::allocate_local_shared< int >( std::allocator(), 5 ); + + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( *pi == 5 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::allocator() ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 0 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::allocate_local_shared_noinit< X >( std::allocator() ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 0 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::allocator(), 1 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::allocator(), 1, 2 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7+8 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8, 9 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7+8+9 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + return boost::report_errors(); +} + +#endif diff --git a/test/allocate_shared_esft_test.cpp b/test/allocate_shared_esft_test.cpp index 2bb8ccc..7902313 100644 --- a/test/allocate_shared_esft_test.cpp +++ b/test/allocate_shared_esft_test.cpp @@ -62,6 +62,28 @@ int main() BOOST_TEST( X::instances == 0 ); + { + boost::shared_ptr< X > px = boost::allocate_shared_noinit< X >( std::allocator() ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + { boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1 ); BOOST_TEST( X::instances == 1 ); diff --git a/test/allocate_shared_test.cpp b/test/allocate_shared_test.cpp index bdae793..31dcc7b 100644 --- a/test/allocate_shared_test.cpp +++ b/test/allocate_shared_test.cpp @@ -61,6 +61,12 @@ int main() BOOST_TEST( *pi == 0 ); } + { + boost::shared_ptr< int > pi = boost::allocate_shared_noinit< int >( std::allocator() ); + + BOOST_TEST( pi.get() != 0 ); + } + { boost::shared_ptr< int > pi = boost::allocate_shared< int >( std::allocator(), 5 ); @@ -83,6 +89,19 @@ int main() BOOST_TEST( X::instances == 0 ); } + { + boost::shared_ptr< X > pi = boost::allocate_shared_noinit< X >( std::allocator() ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 0 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + { boost::shared_ptr< X > pi = boost::allocate_shared< X >( std::allocator(), 1 ); boost::weak_ptr wp( pi ); diff --git a/test/get_local_deleter_array_test.cpp b/test/get_local_deleter_array_test.cpp new file mode 100644 index 0000000..3a8351b --- /dev/null +++ b/test/get_local_deleter_array_test.cpp @@ -0,0 +1,151 @@ +// +// get_local_deleter_array_test2.cpp +// +// Copyright 2002, 2011, 2017 Peter Dimov +// +// 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) +// + +#include +#include + +struct deleter +{ + int data; + + deleter(): data(0) + { + } + + void operator()(void *) + { + BOOST_TEST(data == 17041); + } +}; + +struct deleter2 +{ +}; + +struct X +{ +}; + +int main() +{ + { + boost::local_shared_ptr p; + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + boost::local_shared_ptr p; + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + boost::local_shared_ptr p(new X[1]); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + boost::local_shared_ptr p(new X[1]); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + X x[1]; + boost::local_shared_ptr p(x, deleter()); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + + deleter * q = boost::get_deleter(p); + + BOOST_TEST(q != 0); + BOOST_TEST(q->data == 0); + + q->data = 17041; + + deleter const * r = boost::get_deleter(p); + + BOOST_TEST(r == q); + BOOST_TEST(r->data == 17041); + } + + { + X x[1]; + boost::local_shared_ptr p(x, deleter()); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + + deleter * q = boost::get_deleter(p); + + BOOST_TEST(q != 0); + BOOST_TEST(q->data == 0); + + q->data = 17041; + + deleter const * r = boost::get_deleter(p); + + BOOST_TEST(r == q); + BOOST_TEST(r->data == 17041); + } + + return boost::report_errors(); +} diff --git a/test/get_local_deleter_array_test2.cpp b/test/get_local_deleter_array_test2.cpp new file mode 100644 index 0000000..999fffe --- /dev/null +++ b/test/get_local_deleter_array_test2.cpp @@ -0,0 +1,74 @@ +// +// get_local_deleter_test2.cpp +// +// Copyright 2002, 2017 Peter Dimov +// +// 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) +// + +#include + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) || defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) + +int main() +{ +} + +#else + +#include +#include +#include + +struct deleter +{ +}; + +struct deleter2; + +struct X +{ +}; + +int main() +{ + { + boost::local_shared_ptr p = boost::make_local_shared( 1 ); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + boost::local_shared_ptr p = boost::make_local_shared(); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + return boost::report_errors(); +} + +struct deleter2 +{ +}; + +#endif diff --git a/test/get_local_deleter_test.cpp b/test/get_local_deleter_test.cpp new file mode 100644 index 0000000..8c45af7 --- /dev/null +++ b/test/get_local_deleter_test.cpp @@ -0,0 +1,95 @@ +// +// get_local_deleter_test.cpp +// +// Copyright 2002, 2017 Peter Dimov +// +// 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) +// + +#include +#include + +struct deleter +{ + int data; + + deleter(): data(0) + { + } + + void operator()(void *) + { + BOOST_TEST(data == 17041); + } +}; + +struct deleter2 +{ +}; + +struct X +{ +}; + +int main() +{ + { + boost::local_shared_ptr p; + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + boost::local_shared_ptr p(new X); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + X x; + boost::local_shared_ptr p(&x, deleter()); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + + deleter * q = boost::get_deleter(p); + + BOOST_TEST(q != 0); + BOOST_TEST(q->data == 0); + + q->data = 17041; + + deleter const * r = boost::get_deleter(p); + + BOOST_TEST(r == q); + BOOST_TEST(r->data == 17041); + } + + return boost::report_errors(); +} diff --git a/test/get_local_deleter_test2.cpp b/test/get_local_deleter_test2.cpp new file mode 100644 index 0000000..a0023a9 --- /dev/null +++ b/test/get_local_deleter_test2.cpp @@ -0,0 +1,43 @@ +// +// get_local_deleter_test2.cpp +// +// Copyright 2017 Peter Dimov +// +// 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) +// + +#include +#include + +struct deleter; + +struct X +{ +}; + +static void test_lsp_get_deleter( boost::local_shared_ptr const & p ) +{ + BOOST_TEST( boost::get_deleter( p ) != 0 ); +} + +static void test_sp_get_deleter( boost::shared_ptr const & p ) +{ + BOOST_TEST( boost::get_deleter( p ) != 0 ); +} + +struct deleter +{ + void operator()( X const * p ) { delete p; } +}; + +int main() +{ + boost::local_shared_ptr p( new X, deleter() ); + + test_lsp_get_deleter( p ); + test_sp_get_deleter( p ); + + return boost::report_errors(); +} diff --git a/test/get_local_deleter_test3.cpp b/test/get_local_deleter_test3.cpp new file mode 100644 index 0000000..655c7fc --- /dev/null +++ b/test/get_local_deleter_test3.cpp @@ -0,0 +1,59 @@ +// +// get_local_deleter_test3.cpp +// +// Copyright 2002, 2017 Peter Dimov +// +// 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) +// + +#include + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) || defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) + +int main() +{ +} + +#else + +#include +#include +#include + +struct deleter +{ +}; + +struct deleter2; + +struct X +{ +}; + +int main() +{ + { + boost::local_shared_ptr p = boost::make_local_shared(); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + return boost::report_errors(); +} + +struct deleter2 +{ +}; + +#endif diff --git a/test/local_sp_fn_test.cpp b/test/local_sp_fn_test.cpp new file mode 100644 index 0000000..f2a355a --- /dev/null +++ b/test/local_sp_fn_test.cpp @@ -0,0 +1,43 @@ +// +// local_sp_fn_test.cpp +// +// Copyright 2017 Peter Dimov +// +// 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 +// + +#include +#include +#include + +static void f() +{ +} + +struct null_deleter +{ + template void operator()( Y* ) {} +}; + +int main() +{ + boost::local_shared_ptr pf( f, null_deleter() ); + + BOOST_TEST( pf.get() == f ); + BOOST_TEST_EQ( pf.local_use_count(), 1 ); + BOOST_TEST( boost::get_deleter( pf ) != 0 ); + + boost::weak_ptr wp( pf ); + + BOOST_TEST( wp.lock().get() == f ); + BOOST_TEST_EQ( wp.use_count(), 1 ); + + pf.reset(); + + BOOST_TEST( wp.lock().get() == 0 ); + BOOST_TEST_EQ( wp.use_count(), 0 ); + + return boost::report_errors(); +} diff --git a/test/local_sp_test.cpp b/test/local_sp_test.cpp index b31d498..dc0e316 100644 --- a/test/local_sp_test.cpp +++ b/test/local_sp_test.cpp @@ -9,6 +9,8 @@ // #include +#include +#include #include struct X @@ -1679,6 +1681,809 @@ static void shared_ptr_move_assignment() #endif +// unique_ptr assignment + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) && !defined( BOOST_NO_CXX11_SMART_PTR ) + +template static void empty_unique_ptr_assign_test() +{ + boost::local_shared_ptr p2; + + p2 = std::unique_ptr(); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); + + boost::local_shared_ptr p3; + + p3 = std::unique_ptr(); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); + + boost::local_shared_ptr p4; + + p4 = std::unique_ptr(); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); + + boost::local_shared_ptr p5; + + p5 = std::unique_ptr(); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); +} + +template static void empty_unique_ptr_assign_test_() +{ + boost::local_shared_ptr p2( static_cast(0) ); + + p2 = std::unique_ptr(); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); + + boost::local_shared_ptr p3( static_cast(0) ); + + p3 = std::unique_ptr(); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); + + boost::local_shared_ptr p4( static_cast(0) ); + + p4 = std::unique_ptr(); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); + + boost::local_shared_ptr p5( static_cast(0) ); + + p5 = std::unique_ptr(); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); +} + +template static void test_nonempty_unique_ptr_assign( boost::local_shared_ptr p2, std::unique_ptr && p1 ) +{ + U* q = p1.get(); + + p2 = std::move( p1 ); + + BOOST_TEST_EQ( p2.get(), q ); + BOOST_TEST_EQ( p2.local_use_count(), 1 ); + + BOOST_TEST( p1.get() == 0 ); +} + +template static void new_unique_ptr_assign_test() +{ + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr( new T() ) ); + + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T() ), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T const() ), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T volatile() ), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T const volatile() ), std::unique_ptr( new T() ) ); + + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); +} + +template static void del_unique_ptr_assign_test() +{ + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr>( new T() ) ); + + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T() ), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T const() ), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T volatile() ), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T const volatile() ), std::unique_ptr>( new T() ) ); + + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); +} + +static void unique_ptr_assignment() +{ + empty_unique_ptr_assign_test(); + empty_unique_ptr_assign_test_(); + empty_unique_ptr_assign_test(); + empty_unique_ptr_assign_test_(); + + BOOST_TEST( X::instances == 0 ); + + new_unique_ptr_assign_test(); + new_unique_ptr_assign_test(); + + BOOST_TEST( X::instances == 0 ); + + del_unique_ptr_assign_test(); + del_unique_ptr_assign_test(); + + BOOST_TEST( X::instances == 0 ); +} + +#else + +static void unique_ptr_assignment() +{ +} + +#endif + +// pointer reset + +template static void test_pointer_reset( boost::local_shared_ptr p2 ) +{ + T * q = new T(); + + p2.reset( q ); + + BOOST_TEST_EQ( p2.get(), q ); + BOOST_TEST_EQ( p2.local_use_count(), 1 ); +} + +template static void empty_pointer_reset_test() +{ + test_pointer_reset( boost::local_shared_ptr() ); + test_pointer_reset( boost::local_shared_ptr() ); + test_pointer_reset( boost::local_shared_ptr() ); + test_pointer_reset( boost::local_shared_ptr() ); + + test_pointer_reset( boost::local_shared_ptr() ); + test_pointer_reset( boost::local_shared_ptr() ); + test_pointer_reset( boost::local_shared_ptr() ); + test_pointer_reset( boost::local_shared_ptr() ); +} + +template static void null_pointer_reset_test() +{ + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); +} + +template static void new_pointer_reset_test() +{ + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + test_pointer_reset( boost::local_shared_ptr( new T() ) ); +} + +static void pointer_reset() +{ + empty_pointer_reset_test(); + empty_pointer_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + null_pointer_reset_test(); + null_pointer_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + new_pointer_reset_test(); + new_pointer_reset_test(); + + BOOST_TEST( X::instances == 0 ); +} + +// deleter reset + +template class deleter +{ +private: + + bool * called_; + +public: + + explicit deleter( bool * called ): called_( called ) {} + void operator()( T * p ) { *called_ = true; delete p; } +}; + +template static void test_deleter_reset( boost::local_shared_ptr p2 ) +{ + T * q = new T(); + + bool called = false; + + p2.reset( q, deleter( &called ) ); + + BOOST_TEST_EQ( p2.get(), q ); + BOOST_TEST_EQ( p2.local_use_count(), 1 ); + + boost::shared_ptr p3( p2 ); + + BOOST_TEST( boost::get_deleter< deleter >( p3 ) != 0 ); + + p3.reset(); + BOOST_TEST( !called ); + + p2.reset(); + BOOST_TEST( called ); +} + +template static void empty_deleter_reset_test() +{ + test_deleter_reset( boost::local_shared_ptr() ); + test_deleter_reset( boost::local_shared_ptr() ); + test_deleter_reset( boost::local_shared_ptr() ); + test_deleter_reset( boost::local_shared_ptr() ); + + test_deleter_reset( boost::local_shared_ptr() ); + test_deleter_reset( boost::local_shared_ptr() ); + test_deleter_reset( boost::local_shared_ptr() ); + test_deleter_reset( boost::local_shared_ptr() ); +} + +template static void null_deleter_reset_test() +{ + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); +} + +template static void new_deleter_reset_test() +{ + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + test_deleter_reset( boost::local_shared_ptr( new T() ) ); +} + +static void deleter_reset() +{ + empty_deleter_reset_test(); + empty_deleter_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + null_deleter_reset_test(); + null_deleter_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + new_deleter_reset_test(); + new_deleter_reset_test(); + + BOOST_TEST( X::instances == 0 ); +} + +// allocator reset + +template static void test_allocator_reset( boost::local_shared_ptr p2 ) +{ + T * q = new T(); + + bool called = false; + + p2.reset( q, deleter( &called ), std::allocator() ); + + BOOST_TEST_EQ( p2.get(), q ); + BOOST_TEST_EQ( p2.local_use_count(), 1 ); + + boost::shared_ptr p3( p2 ); + + BOOST_TEST( boost::get_deleter< deleter >( p3 ) != 0 ); + + p3.reset(); + BOOST_TEST( !called ); + + p2.reset(); + BOOST_TEST( called ); +} + +template static void empty_allocator_reset_test() +{ + test_allocator_reset( boost::local_shared_ptr() ); + test_allocator_reset( boost::local_shared_ptr() ); + test_allocator_reset( boost::local_shared_ptr() ); + test_allocator_reset( boost::local_shared_ptr() ); + + test_allocator_reset( boost::local_shared_ptr() ); + test_allocator_reset( boost::local_shared_ptr() ); + test_allocator_reset( boost::local_shared_ptr() ); + test_allocator_reset( boost::local_shared_ptr() ); +} + +template static void null_allocator_reset_test() +{ + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); +} + +template static void new_allocator_reset_test() +{ + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + test_allocator_reset( boost::local_shared_ptr( new T() ) ); +} + +static void allocator_reset() +{ + empty_allocator_reset_test(); + empty_allocator_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + null_allocator_reset_test(); + null_allocator_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + new_allocator_reset_test(); + new_allocator_reset_test(); + + BOOST_TEST( X::instances == 0 ); +} + +// aliasing reset + +struct null_deleter +{ + void operator()( void const volatile* ) {} +}; + +template void test_aliasing_reset_( boost::local_shared_ptr const & p1, U * p2 ) +{ + boost::local_shared_ptr p3( static_cast(0), null_deleter() ); + + p3.reset( p1, p2 ); + + BOOST_TEST( p3.get() == p2 ); + BOOST_TEST( p3.local_use_count() == p1.local_use_count() ); + BOOST_TEST( !p3.owner_before( p1 ) && !p1.owner_before( p3 ) ); +} + +template void test_01_aliasing_reset_() +{ + U u; + boost::local_shared_ptr p1; + + test_aliasing_reset_( p1, &u ); +} + +template void test_01_aliasing_reset() +{ + test_01_aliasing_reset_(); + test_01_aliasing_reset_(); + test_01_aliasing_reset_(); + test_01_aliasing_reset_(); + + test_01_aliasing_reset_(); + test_01_aliasing_reset_(); + test_01_aliasing_reset_(); + test_01_aliasing_reset_(); +} + +template void test_10_aliasing_reset_() +{ + boost::local_shared_ptr p1( new T() ); + test_aliasing_reset_( p1, static_cast(0) ); +} + +template void test_10_aliasing_reset() +{ + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); +} + +template void test_11_aliasing_reset_() +{ + U u; + boost::local_shared_ptr p1( new T() ); + + test_aliasing_reset_( p1, &u ); +} + +template void test_11_aliasing_reset() +{ + test_11_aliasing_reset_(); + test_11_aliasing_reset_(); + test_11_aliasing_reset_(); + test_11_aliasing_reset_(); + + test_11_aliasing_reset_(); + test_11_aliasing_reset_(); + test_11_aliasing_reset_(); + test_11_aliasing_reset_(); +} + +static void aliasing_reset() +{ + test_01_aliasing_reset(); + test_10_aliasing_reset(); + test_11_aliasing_reset(); + + test_01_aliasing_reset(); + + test_10_aliasing_reset(); + + test_10_aliasing_reset(); + + test_01_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_10_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_11_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_01_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_10_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_11_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_01_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_10_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_11_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_01_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_10_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_10_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); +} + +// element access + +template static void empty_element_access_() +{ + boost::local_shared_ptr p1; + + BOOST_TEST_EQ( p1.operator->(), static_cast(0) ); + BOOST_TEST_EQ( p1.get(), static_cast(0) ); + BOOST_TEST( p1? false: true ); + BOOST_TEST( !p1 ); + BOOST_TEST_EQ( p1.local_use_count(), 0 ); +} + +template static void empty_element_access() +{ + empty_element_access_(); + empty_element_access_(); + empty_element_access_(); + empty_element_access_(); +} + +template static void new_element_access_() +{ + { + T * p0 = new T(); + boost::local_shared_ptr p1( p0 ); + + BOOST_TEST_EQ( p1.operator->(), p0 ); + BOOST_TEST_EQ( p1.get(), p0 ); + BOOST_TEST_EQ( &*p1, p0 ); + BOOST_TEST( p1? true: false ); + BOOST_TEST_NOT( !p1 ); + BOOST_TEST_EQ( p1.local_use_count(), 1 ); + } + + { + T * p0 = new T[3](); + boost::local_shared_ptr p1( p0 ); + + BOOST_TEST_EQ( p1.get(), p0 ); + + BOOST_TEST_EQ( &p1[0], &p0[0] ); + BOOST_TEST_EQ( &p1[1], &p0[1] ); + BOOST_TEST_EQ( &p1[2], &p0[2] ); + + BOOST_TEST( p1? true: false ); + BOOST_TEST_NOT( !p1 ); + BOOST_TEST_EQ( p1.local_use_count(), 1 ); + } + + { + T * p0 = new T[3](); + boost::local_shared_ptr p1( p0 ); + + BOOST_TEST_EQ( p1.get(), p0 ); + + BOOST_TEST_EQ( &p1[0], &p0[0] ); + BOOST_TEST_EQ( &p1[1], &p0[1] ); + BOOST_TEST_EQ( &p1[2], &p0[2] ); + + BOOST_TEST( p1? true: false ); + BOOST_TEST_NOT( !p1 ); + BOOST_TEST_EQ( p1.local_use_count(), 1 ); + } +} + +template static void new_element_access() +{ + new_element_access_(); + new_element_access_(); + new_element_access_(); + new_element_access_(); +} + +static void element_access() +{ + empty_element_access(); + empty_element_access(); + + BOOST_TEST( X::instances == 0 ); + + empty_element_access(); + empty_element_access(); + + new_element_access(); + new_element_access(); + + BOOST_TEST( X::instances == 0 ); +} + +// shared_ptr conversion + +template static void empty_shared_ptr_conversion_() +{ + boost::local_shared_ptr p1; + boost::shared_ptr p2( p1 ); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.use_count(), 0 ); +} + +template static void empty_shared_ptr_conversion() +{ + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); +} + +template static void new_shared_ptr_conversion_() +{ + boost::local_shared_ptr p1( new T() ); + boost::shared_ptr p2( p1 ); + + BOOST_TEST_EQ( p2.get(), p1.get() ); + BOOST_TEST_EQ( p2.use_count(), 2 ); + + boost::shared_ptr p3( p1 ); + + BOOST_TEST_EQ( p3.get(), p1.get() ); + BOOST_TEST_EQ( p3.use_count(), 3 ); + BOOST_TEST( !(p2 < p3) && !(p3 < p2) ); + + BOOST_TEST_EQ( p1.local_use_count(), 1 ); + + p1.reset(); + + BOOST_TEST_EQ( p2.use_count(), 2 ); + BOOST_TEST_EQ( p3.use_count(), 2 ); +} + +template static void new_shared_ptr_conversion() +{ + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); +} + +static void shared_ptr_conversion() +{ + empty_shared_ptr_conversion(); + empty_shared_ptr_conversion(); + empty_shared_ptr_conversion(); + empty_shared_ptr_conversion(); + + BOOST_TEST( X::instances == 0 ); + + new_shared_ptr_conversion(); + new_shared_ptr_conversion(); + + BOOST_TEST( X::instances == 0 ); +} + +// weak_ptr conversion + +template static void empty_weak_ptr_conversion_() +{ + boost::local_shared_ptr p1; + boost::weak_ptr p2( p1 ); + + BOOST_TEST_EQ( p2.lock().get(), static_cast(0) ); + BOOST_TEST_EQ( p2.use_count(), 0 ); +} + +template static void empty_weak_ptr_conversion() +{ + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); +} + +template static void new_weak_ptr_conversion_() +{ + boost::local_shared_ptr p1( new T() ); + boost::weak_ptr p2( p1 ); + + BOOST_TEST_EQ( p2.lock().get(), p1.get() ); + BOOST_TEST_EQ( p2.use_count(), 1 ); + + boost::weak_ptr p3( p1 ); + + BOOST_TEST_EQ( p3.lock().get(), p1.get() ); + BOOST_TEST_EQ( p3.use_count(), 1 ); + BOOST_TEST( !(p2 < p3) && !(p3 < p2) ); + + BOOST_TEST_EQ( p1.local_use_count(), 1 ); + + p1.reset(); + + BOOST_TEST_EQ( p2.use_count(), 0 ); + BOOST_TEST_EQ( p3.use_count(), 0 ); +} + +template static void new_weak_ptr_conversion() +{ + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); +} + +static void weak_ptr_conversion() +{ + empty_weak_ptr_conversion(); + empty_weak_ptr_conversion(); + empty_weak_ptr_conversion(); + empty_weak_ptr_conversion(); + + BOOST_TEST( X::instances == 0 ); + + new_weak_ptr_conversion(); + new_weak_ptr_conversion(); + + BOOST_TEST( X::instances == 0 ); +} + // main int main() @@ -1702,18 +2507,25 @@ int main() nullptr_assignment(); shared_ptr_copy_assignment(); shared_ptr_move_assignment(); - // unique_ptr_assignment(); + unique_ptr_assignment(); default_reset(); - // pointer_reset(); - // deleter_reset(); - // allocator_reset(); - // aliasing_reset(); + pointer_reset(); + deleter_reset(); + allocator_reset(); + aliasing_reset(); - // element_access(); + element_access(); + shared_ptr_conversion(); + weak_ptr_conversion(); // swap_test(); // owner_before_test(); // equal_test(); + // operator< ? + // casts + // get_pointer + // operator<< + // hash return boost::report_errors(); } diff --git a/test/make_local_shared_esft_test.cpp b/test/make_local_shared_esft_test.cpp new file mode 100644 index 0000000..95b651e --- /dev/null +++ b/test/make_local_shared_esft_test.cpp @@ -0,0 +1,297 @@ +// make_local_shared_esft_test.cpp +// +// Copyright 2007-2009, 2017 Peter Dimov +// +// 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 + +#include + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) || defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) + +int main() +{ +} + +#else + +#include +#include +#include +#include + +class X: public boost::enable_shared_from_this +{ +private: + + X( X const & ); + X & operator=( X const & ); + +public: + + static int instances; + + explicit X( int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0 ) + { + ++instances; + } + + ~X() + { + --instances; + } +}; + +int X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_local_shared< X >(); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_local_shared_noinit< X >(); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_local_shared< X >( 1 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_local_shared< X >( 1, 2 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_local_shared< X >( 1, 2, 3 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_local_shared< X >( 1, 2, 3, 4 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_local_shared< X >( 1, 2, 3, 4, 5 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_local_shared< X >( 1, 2, 3, 4, 5, 6 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_local_shared< X >( 1, 2, 3, 4, 5, 6, 7 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_local_shared< X >( 1, 2, 3, 4, 5, 6, 7, 8 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_local_shared< X >( 1, 2, 3, 4, 5, 6, 7, 8, 9 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + return boost::report_errors(); +} + +#endif diff --git a/test/make_local_shared_test.cpp b/test/make_local_shared_test.cpp new file mode 100644 index 0000000..c5f7fe3 --- /dev/null +++ b/test/make_local_shared_test.cpp @@ -0,0 +1,235 @@ +// make_local_shared_test.cpp +// +// Copyright 2007-2009, 2017 Peter Dimov +// +// 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 + +#include + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) || defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) + +int main() +{ +} + +#else + +#include +#include +#include +#include +#include + +class X +{ +private: + + X( X const & ); + X & operator=( X const & ); + + void * operator new( std::size_t n ) + { + // lack of this definition causes link errors on Comeau C++ + BOOST_ERROR( "private X::new called" ); + return ::operator new( n ); + } + + void operator delete( void * p ) + { + // lack of this definition causes link errors on MSVC + BOOST_ERROR( "private X::delete called" ); + ::operator delete( p ); + } + +public: + + static int instances; + + int v; + + explicit X( int a1 = 0, int a2 = 0, int a3 = 0, int a4 = 0, int a5 = 0, int a6 = 0, int a7 = 0, int a8 = 0, int a9 = 0 ): v( a1+a2+a3+a4+a5+a6+a7+a8+a9 ) + { + ++instances; + } + + ~X() + { + --instances; + } +}; + +int X::instances = 0; + +int main() +{ + { + boost::local_shared_ptr< int > pi = boost::make_local_shared< int >(); + + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( *pi == 0 ); + } + + { + boost::local_shared_ptr< int > pi = boost::make_local_shared_noinit< int >(); + + BOOST_TEST( pi.get() != 0 ); + } + + { + boost::local_shared_ptr< int > pi = boost::make_local_shared< int >( 5 ); + + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( *pi == 5 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::local_shared_ptr< X > pi = boost::make_local_shared< X >(); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 0 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::make_local_shared_noinit< X >(); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 0 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::make_local_shared< X >( 1 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::make_local_shared< X >( 1, 2 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::make_local_shared< X >( 1, 2, 3 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::make_local_shared< X >( 1, 2, 3, 4 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::make_local_shared< X >( 1, 2, 3, 4, 5 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::make_local_shared< X >( 1, 2, 3, 4, 5, 6 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::make_local_shared< X >( 1, 2, 3, 4, 5, 6, 7 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::make_local_shared< X >( 1, 2, 3, 4, 5, 6, 7, 8 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7+8 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::local_shared_ptr< X > pi = boost::make_local_shared< X >( 1, 2, 3, 4, 5, 6, 7, 8, 9 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7+8+9 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + return boost::report_errors(); +} + +#endif diff --git a/test/make_shared_esft_test.cpp b/test/make_shared_esft_test.cpp index 1956cba..cbd31d0 100644 --- a/test/make_shared_esft_test.cpp +++ b/test/make_shared_esft_test.cpp @@ -61,6 +61,28 @@ int main() BOOST_TEST( X::instances == 0 ); + { + boost::shared_ptr< X > px = boost::make_shared_noinit< X >(); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + { boost::shared_ptr< X > px = boost::make_shared< X >( 1 ); BOOST_TEST( X::instances == 1 ); diff --git a/test/make_shared_test.cpp b/test/make_shared_test.cpp index 9ebc3fa..aff9b7c 100644 --- a/test/make_shared_test.cpp +++ b/test/make_shared_test.cpp @@ -61,6 +61,12 @@ int main() BOOST_TEST( *pi == 0 ); } + { + boost::shared_ptr< int > pi = boost::make_shared_noinit< int >(); + + BOOST_TEST( pi.get() != 0 ); + } + { boost::shared_ptr< int > pi = boost::make_shared< int >( 5 ); @@ -83,6 +89,19 @@ int main() BOOST_TEST( X::instances == 0 ); } + { + boost::shared_ptr< X > pi = boost::make_shared_noinit< X >(); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 0 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + { boost::shared_ptr< X > pi = boost::make_shared< X >( 1 ); boost::weak_ptr wp( pi );