1 #ifndef BOOST_SMART_PTR_MAKE_LOCAL_SHARED_OBJECT_HPP_INCLUDED
2 #define BOOST_SMART_PTR_MAKE_LOCAL_SHARED_OBJECT_HPP_INCLUDED
3
4 // make_local_shared_object.hpp
5 //
6 // Copyright 2017 Peter Dimov
7 //
8 // Distributed under the Boost Software License, Version 1.0.
9 // See accompanying file LICENSE_1_0.txt or copy at
10 // http://www.boost.org/LICENSE_1_0.txt
11 //
12 // See http://www.boost.org/libs/smart_ptr/ for documentation.
13
14 #include <boost/smart_ptr/local_shared_ptr.hpp>
15 #include <boost/smart_ptr/make_shared.hpp>
16 #include <boost/type_traits/remove_const.hpp>
17 #include <boost/config.hpp>
18 #include <utility>
19 #include <cstddef>
20
21 namespace boost
22 {
23
24 namespace detail
25 {
26
27 // lsp_if_not_array
28
29 template<class T> struct lsp_if_not_array
30 {
31 typedef boost::local_shared_ptr<T> type;
32 };
33
34 template<class T> struct lsp_if_not_array<T[]>
35 {
36 };
37
38 template<class T, std::size_t N> struct lsp_if_not_array<T[N]>
39 {
40 };
41
42 // lsp_ms_deleter
43
44 template<class T, class A> class lsp_ms_deleter: public local_counted_impl_em
45 {
46 private:
47
48 typedef typename sp_aligned_storage<sizeof(T), ::boost::alignment_of<T>::value>::type storage_type;
49
50 storage_type storage_;
51 A a_;
52 bool initialized_;
53
54 private:
55
destroy()56 void destroy() BOOST_SP_NOEXCEPT
57 {
58 if( initialized_ )
59 {
60 T * p = reinterpret_cast< T* >( storage_.data_ );
61
62 #if !defined( BOOST_NO_CXX11_ALLOCATOR )
63
64 std::allocator_traits<A>::destroy( a_, p );
65
66 #else
67
68 p->~T();
69
70 #endif
71
72 initialized_ = false;
73 }
74 }
75
76 public:
77
lsp_ms_deleter(A const & a)78 explicit lsp_ms_deleter( A const & a ) BOOST_SP_NOEXCEPT : a_( a ), initialized_( false )
79 {
80 }
81
82 // optimization: do not copy storage_
lsp_ms_deleter(lsp_ms_deleter const & r)83 lsp_ms_deleter( lsp_ms_deleter const & r ) BOOST_SP_NOEXCEPT : a_( r.a_), initialized_( false )
84 {
85 }
86
~lsp_ms_deleter()87 ~lsp_ms_deleter() BOOST_SP_NOEXCEPT
88 {
89 destroy();
90 }
91
operator ()(T *)92 void operator()( T * ) BOOST_SP_NOEXCEPT
93 {
94 destroy();
95 }
96
operator_fn(T *)97 static void operator_fn( T* ) BOOST_SP_NOEXCEPT // operator() can't be static
98 {
99 }
100
address()101 void * address() BOOST_SP_NOEXCEPT
102 {
103 return storage_.data_;
104 }
105
set_initialized()106 void set_initialized() BOOST_SP_NOEXCEPT
107 {
108 initialized_ = true;
109 }
110 };
111
112 } // namespace detail
113
allocate_local_shared(A const & a,Args &&...args)114 template<class T, class A, class... Args> typename boost::detail::lsp_if_not_array<T>::type allocate_local_shared( A const & a, Args&&... args )
115 {
116 #if !defined( BOOST_NO_CXX11_ALLOCATOR )
117
118 typedef typename std::allocator_traits<A>::template rebind_alloc<T> A2;
119
120 #else
121
122 typedef typename A::template rebind<T>::other A2;
123
124 #endif
125
126 A2 a2( a );
127
128 typedef boost::detail::lsp_ms_deleter<T, A2> D;
129
130 boost::shared_ptr<T> pt( static_cast< T* >( 0 ), boost::detail::sp_inplace_tag<D>(), a2 );
131
132 D * pd = static_cast< D* >( pt._internal_get_untyped_deleter() );
133 void * pv = pd->address();
134
135 #if !defined( BOOST_NO_CXX11_ALLOCATOR )
136
137 std::allocator_traits<A2>::construct( a2, static_cast< T* >( pv ), std::forward<Args>( args )... );
138
139 #else
140
141 ::new( pv ) T( std::forward<Args>( args )... );
142
143 #endif
144
145 pd->set_initialized();
146
147 T * pt2 = static_cast< T* >( pv );
148 boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
149
150 pd->pn_ = pt._internal_count();
151
152 return boost::local_shared_ptr<T>( boost::detail::lsp_internal_constructor_tag(), pt2, pd );
153 }
154
allocate_local_shared_noinit(A const & a)155 template<class T, class A> typename boost::detail::lsp_if_not_array<T>::type allocate_local_shared_noinit( A const & a )
156 {
157 #if !defined( BOOST_NO_CXX11_ALLOCATOR )
158
159 typedef typename std::allocator_traits<A>::template rebind_alloc<T> A2;
160
161 #else
162
163 typedef typename A::template rebind<T>::other A2;
164
165 #endif
166
167 A2 a2( a );
168
169 typedef boost::detail::lsp_ms_deleter< T, std::allocator<T> > D;
170
171 boost::shared_ptr<T> pt( static_cast< T* >( 0 ), boost::detail::sp_inplace_tag<D>(), a2 );
172
173 D * pd = static_cast< D* >( pt._internal_get_untyped_deleter() );
174 void * pv = pd->address();
175
176 ::new( pv ) T;
177
178 pd->set_initialized();
179
180 T * pt2 = static_cast< T* >( pv );
181 boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
182
183 pd->pn_ = pt._internal_count();
184
185 return boost::local_shared_ptr<T>( boost::detail::lsp_internal_constructor_tag(), pt2, pd );
186 }
187
make_local_shared(Args &&...args)188 template<class T, class... Args> typename boost::detail::lsp_if_not_array<T>::type make_local_shared( Args&&... args )
189 {
190 typedef typename boost::remove_const<T>::type T2;
191 return boost::allocate_local_shared<T2>( std::allocator<T2>(), std::forward<Args>(args)... );
192 }
193
make_local_shared_noinit()194 template<class T> typename boost::detail::lsp_if_not_array<T>::type make_local_shared_noinit()
195 {
196 typedef typename boost::remove_const<T>::type T2;
197 return boost::allocate_shared_noinit<T2>( std::allocator<T2>() );
198 }
199
200 } // namespace boost
201
202 #endif // #ifndef BOOST_SMART_PTR_MAKE_SHARED_OBJECT_HPP_INCLUDED
203