libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
shared_ptr_impl.hpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2004 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 #include "dynamic_cast.hpp"
20 
21 #include <boost/mpl/assert.hpp>
22 
23 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE {
24 
25  template<class V, class LkT> inline typename shared_ptr<V, LkT>::atomic_ptr_t
26  shared_ptr<V, LkT>::release() noexcept(true) {
27  // Check that another thread hasn't already deleted the controlled object.
28  if (data_.get()) {
29  // tmp is not shared, so no need to be atomic.
30  typename atomic_ptr_t::value_type tmp=static_cast<typename atomic_ptr_t::value_type>(data_.get());
31  assert(dynamic_cast<typename atomic_ptr_t::value_type>(tmp));
32  assert(tmp->sp_count()>0);
33  // This operation is atomic: only one thread will achieve a zero reference count.
34  if (LIKELY(tmp->sp_release())) {
35  assert(tmp->sp_count()<=0);
36  // Signal deleted to this thread.
37  data_=typename atomic_ptr_t::value_type();
38  }
39  // Only one thread will call the deleter, because the sp_release() operation was atomic.
40  const bool ret=(!data_ && dynamic_cast<typename atomic_ptr_t::value_type>(tmp));
41  if (LIKELY(ret)) {
42  assert(dynamic_cast<ctr_type *>(tmp));
43  tmp->deleter();
44  }
45  }
46  return data_;
47  }
48 
49  template<class V, class LkT> inline void
50  shared_ptr<V, LkT>::reset() noexcept(true) {
51  shared_ptr().swap(*this);
52  }
53 
54  template<class V, class LkT> inline
55  shared_ptr<V, LkT>::shared_ptr(value_type *ptr) noexcept(true)
56  : data_(ptr) {
57  BOOST_MPL_ASSERT((std::is_same<deleter_t, typename value_type::deleter_t>));
58  if (LIKELY(ptr)) {
59  assert(dynamic_cast<ctr_type *>(ptr));
60  ptr->sp_acquire();
61  assert(dynamic_cast<value_type *>(data_.get()));
62  assert(ptr->sp_count()>0);
63  }
64  }
65 
66  template<class V, class LkT>
67  template<class V1>
68  inline
69  shared_ptr<V, LkT>::shared_ptr(V1 *ptr) noexcept(true)
70  : data_() {
71  typedef typename std::remove_const<V1>::type v1_t;
72 
73  BOOST_MPL_ASSERT((std::is_base_of<base_ctr_type, v1_t>));
74 // This is too stringent a test, as it ignores common bases: BOOST_MPL_ASSERT((std::is_base_of<value_type, v1_t>));
75 // This is too stringent a test, as it ignores virtual dtors: BOOST_MPL_ASSERT((std::is_same<deleter_t, typename V1::deleter_t>));
76  if (LIKELY(ptr)) {
77  assert(dynamic_cast<v1_t *>(ptr));
78  assert(dynamic_cast<ctr_type const *>(ptr));
79  ptr->sp_acquire();
80  data_=static_cast<value_type *>(const_cast<v1_t *>(ptr));
81  assert(dynamic_cast<value_type *>(data_.get()));
82  assert(ptr->sp_count()>0);
83  }
84  }
85 
86  template<class V, class LkT> inline
87  shared_ptr<V, LkT>::shared_ptr(atomic_ptr_t const &ptr) noexcept(true)
88  : data_(ptr) {
89  BOOST_MPL_ASSERT((std::is_same<deleter_t, typename value_type::deleter_t>));
90  if (LIKELY(ptr.get())) {
91  assert(dynamic_cast<ctr_type *>(ptr.get()));
92  ptr->sp_acquire();
93  assert(dynamic_cast<value_type *>(data_.get()));
94  assert(ptr->sp_count()>0);
95  }
96  }
97 
98  template<class V, class LkT>
99  template<class V1>
100  inline
101  shared_ptr<V, LkT>::shared_ptr(sp_counter_itf_type<V1> const &ptr) noexcept(true)
102  : data_(ptr) {
103  BOOST_MPL_ASSERT((std::is_same<deleter_t, typename value_type::deleter_t>));
104  if (LIKELY(ptr.get())) {
105  assert(dynamic_cast<ctr_type *>(ptr.get()));
106  ptr->sp_acquire();
107  assert(dynamic_cast<value_type *>(data_.get()));
108  assert(ptr->sp_count()>0);
109  }
110  }
111 
112  template<class V, class LkT>
113  template<class V1, template<class> class At>
114  inline
115  shared_ptr<V, LkT>::shared_ptr(At<V1*> const &ptr) noexcept(true)
116  : data_(ptr) {
117  BOOST_MPL_ASSERT((std::is_base_of<value_type, V1>));
118  BOOST_MPL_ASSERT((std::is_base_of<base_ctr_type, V1>));
119 // This is too stringent a test, as it ignores virtual dtors: BOOST_MPL_ASSERT((std::is_same<deleter_t, typename V1::deleter_t>));
120  if (LIKELY(ptr.get())) {
121  assert(dynamic_cast<V1 *>(ptr.get()));
122  assert(dynamic_cast<ctr_type *>(ptr.get()));
123  ptr->sp_acquire();
124  assert(dynamic_cast<value_type *>(data_.get()));
125  assert(ptr->sp_count()>0);
126  }
127  }
128 
129  template<class V, class LkT> inline
130  shared_ptr<V, LkT>::shared_ptr(std::unique_ptr<value_type, deleter_t> &d) noexcept(true)
131  : data_() {
132  if (LIKELY(d.get())) {
133  assert(dynamic_cast<ctr_type *>(d.get()));
134  d->sp_acquire();
135  data_=d.release();
136  assert(dynamic_cast<value_type *>(data_.get()));
137  assert(data_->sp_count()>0);
138  }
139  }
140 
141  template<class V, class LkT>
142  template<class V1>
143  inline
144  shared_ptr<V, LkT>::shared_ptr(std::unique_ptr<V1, typename V1::deleter_t> &d) noexcept(true)
145  : data_() {
146  BOOST_MPL_ASSERT((std::is_base_of<value_type, V1>));
147  BOOST_MPL_ASSERT((std::is_base_of<base_ctr_type, V1>));
148  BOOST_MPL_ASSERT((std::is_same<deleter_t, typename V1::deleter_t>));
149  if (LIKELY(d.get())) {
150  assert(dynamic_cast<ctr_type *>(d.get()));
151  d->sp_acquire();
152  data_=static_cast<value_type *>(d.release());
153  assert(dynamic_cast<value_type *>(data_));
154  assert(data_->sp_count()>0);
155  }
156  }
157 
158  template<class V, class LkT> inline
159  shared_ptr<V, LkT>::shared_ptr(std::unique_ptr<value_type, deleter_t> &&d) noexcept(true)
160  : data_(d.release()) {
161  if (LIKELY(data_.get())) {
162  assert(dynamic_cast<ctr_type *>(data_.get()));
163  data_->sp_acquire();
164  assert(dynamic_cast<value_type *>(data_.get()));
165  assert(data_->sp_count()>0);
166  }
167  }
168 
169  template<class V, class LkT>
170  template<class V1>
171  inline
172  shared_ptr<V, LkT>::shared_ptr(std::unique_ptr<V1, typename V1::deleter_t> &&d) noexcept(true)
173  : data_(d.release()) {
174  BOOST_MPL_ASSERT((std::is_base_of<value_type, V1>));
175  BOOST_MPL_ASSERT((std::is_base_of<base_ctr_type, V1>));
176  // I want to test that if the dtor is dynamic alloc, then the V1::element_type is derived from value_type, otherwise if placement, the dtor must be the same, otherwise if noop_dtor, don't care.
177 // This is too stringent a test, as it ignores virtual dtors: BOOST_MPL_ASSERT((std::is_same<deleter_t, typename V1::deleter_t>));
178 // static_assert(std::is_base_of<deleter_t, typename V1::deleter_t>::value || std::is_base_of<typename V1::deleter_t, deleter_t>::value, "TODO");
179  if (LIKELY(data_.get())) {
180  assert(dynamic_cast<ctr_type *>(d.get()));
181  data_->sp_acquire();
182  assert(dynamic_cast<value_type *>(data_));
183  assert(data_->sp_count()>0);
184  }
185  }
186 
187  template<class V, class LkT> inline
188  shared_ptr<V, LkT>::shared_ptr(const shared_ptr &s) noexcept(true)
189  : data_() {
190  // Also check greater than one, because a dtor could delete the object whilst we're doing the "*s.data" operation.
191  const bool ret=(s.data_.get() && s.data_->sp_acquire()>1);
192  if (LIKELY(ret)) {
193  assert(dynamic_cast<ctr_type *>(s.data_.get()));
194  data_=s.data_;
195  assert(data_==s.data_);
196  assert(dynamic_cast<value_type *>(data_.get()));
197  assert(data_->sp_count()>0);
198  }
199  }
200 
201  template<class V, class LkT> inline
202  shared_ptr<V, LkT>::shared_ptr(shared_ptr &&s) noexcept(true)
203  : data_() {
204  data_.swap(s.data_);
205  assert(data_.get() ? data_->sp_count()>0 : true);
206  }
207 
208  template<class V, class LkT>
209  template<typename V2, class LkT2> inline
210  shared_ptr<V, LkT>::shared_ptr(const shared_ptr<V2, LkT2> &s) noexcept(true)
211  : data_() {
212  typedef typename shared_ptr<V2, LkT2>::ctr_type ctr2_type;
213 // This is too stringent a test, as it ignores common bases BOOST_MPL_ASSERT((std::is_base_of<value_type, V2>));
214  BOOST_MPL_ASSERT((std::is_base_of<base_ctr_type, V2>));
215  BOOST_MPL_ASSERT((std::is_base_of<base_ctr_type, ctr2_type>));
216 // This is too stringent a test, as it ignores virtual dtors: BOOST_MPL_ASSERT((std::is_same<deleter_t, typename V2::deleter_t>));
217  // Also check greater than one, because a dtor could execute in another thread on the same object, whilst we're doing the "*s.data" operation.
218  const bool ret=(s.data_.get() && s.data_->sp_acquire()>1);
219  if (LIKELY(ret)) {
220  assert(dynamic_cast<ctr2_type *>(s.data_.get()));
221  data_=s.data_;
222  assert(data_==s.data_);
223  assert(dynamic_cast<value_type *>(data_.get()));
224  assert(data_.get() ? data_->sp_count()>0 : true);
225  }
226  }
227 
228  template<class V, class LkT>
229  template<typename V2, class LkT2> inline
230  shared_ptr<V, LkT>::shared_ptr(shared_ptr<V2, LkT2> &&s) noexcept(true)
231  : data_() {
232  BOOST_MPL_ASSERT((std::is_base_of<value_type, V2>));
233  BOOST_MPL_ASSERT((std::is_base_of<base_ctr_type, V2>));
234  BOOST_MPL_ASSERT((std::is_same<base_ctr_type, typename V2::base_ctr_type>));
235  data_.swap(s.data_);
236  assert(data_.get() ? data_->sp_count()>0 : true);
237  }
238 
239  template<class V, class LkT> inline
240  shared_ptr<V, LkT>::~shared_ptr() noexcept(true) {
242  }
243 
244  template<class V, class LkT> inline void
245  shared_ptr<V, LkT>::swap(shared_ptr &s) noexcept(true) {
246  data_.swap(s.data_);
247  assert(data_.get() ? data_->sp_count()>0 : true);
248  }
249 
250  template<class V, class LkT>
251  template<typename V2, class LkT2> inline void
252  shared_ptr<V, LkT>::operator=(const shared_ptr<V2, LkT2> &s) noexcept(true) {
253  BOOST_MPL_ASSERT((std::is_base_of<value_type, V2>));
254  BOOST_MPL_ASSERT((std::is_base_of<base_ctr_type, V2>));
255  BOOST_MPL_ASSERT((std::is_same<base_ctr_type, typename V2::base_ctr_type>));
256  shared_ptr tmp(s);
257  tmp.swap(*this);
258  assert(data_.get() ? data_->sp_count()>0 : true);
259  }
260 
261  template<class V, class LkT>
262  template<typename V2, class LkT2> inline void
263  shared_ptr<V, LkT>::operator=(shared_ptr<V2, LkT2> &&s) noexcept(true) {
264  data_.swap(s.data_);
265  assert(data_.get() ? data_->sp_count()>0 : true);
266  }
267 
268  template<class V, class LkT> inline void
269  shared_ptr<V, LkT>::operator=(const shared_ptr<V, LkT> &s) noexcept(true) {
270  shared_ptr tmp(s);
271  tmp.swap(*this);
272  assert(data_.get() ? data_->sp_count()>0 : true);
273  }
274 
275  template<class V, class LkT> inline void
276  shared_ptr<V, LkT>::operator=(shared_ptr<V, LkT> &&s) noexcept(true) {
277  data_.swap(s.data_);
278  assert(data_.get() ? data_->sp_count()>0 : true);
279  }
280 
281  template<class V, class LkT> constexpr inline bool
282  shared_ptr<V, LkT>::operator<(const shared_ptr &s) const noexcept(true) {
283  return (data_.get() && s.data_.get()) ? (*data_.get()<*s.data_.get()) : false;
284  }
285  template<class V, class LkT> constexpr inline bool
286  shared_ptr<V, LkT>::operator==(const shared_ptr &s) const noexcept(true) {
287  return !((data_<s.data_) || (s.data_<data_));
288  }
289  template<class V, class LkT> inline constexpr bool
290  shared_ptr<V, LkT>::operator!=(const shared_ptr &s) const noexcept(true) {
291  return !(*this==s);
292  }
293  template<class V, class LkT> constexpr inline
294  shared_ptr<V, LkT>::operator bool() const noexcept(true) {
295  return dynamic_cast<value_type const *>(data_.get())!=nullptr;
296  }
297  template<class V, class LkT> constexpr inline bool
298  shared_ptr<V, LkT>::operator>(const shared_ptr &s) const noexcept(true) {
299  return (data_!=s.data_) && (s.data_<data_);
300  }
301 
302  template<class V, class LkT> constexpr inline typename shared_ptr<V, LkT>::atomic_ptr_t const &
303  shared_ptr<V, LkT>::get() const noexcept(true) {
304  return data_;
305  }
306  template<class V, class LkT> inline typename shared_ptr<V, LkT>::atomic_ptr_t &
307  shared_ptr<V, LkT>::get() noexcept(true) {
308  return data_;
309  }
310  template<class V, class LkT> constexpr inline typename shared_ptr<V, LkT>::value_type const &
311  shared_ptr<V, LkT>::operator*() const noexcept(true) {
312  assert(dynamic_cast<value_type const *>(data_.get()));
313  return *data_.get();
314  }
315  template<class V, class LkT> inline typename shared_ptr<V, LkT>::value_type &
316  shared_ptr<V, LkT>::operator*() noexcept(true) {
317  assert(dynamic_cast<value_type *>(data_.get()));
318  return *data_.get();
319  }
320  template<class V, class LkT> constexpr inline typename shared_ptr<V, LkT>::value_type const *
321  shared_ptr<V, LkT>::operator->() const noexcept(true) {
322  return data_.get();
323  }
324  template<class V, class LkT> inline typename shared_ptr<V, LkT>::value_type *
325  shared_ptr<V, LkT>::operator->() noexcept(true) {
326  return data_.get();
327  }
328 
329  template<class V, class LkT> inline tstring
330  shared_ptr<V, LkT>::to_string() const noexcept(false) {
331  tostringstream os;
332  os<<"data_="<<data_.get();
333  if (LIKELY(dynamic_cast<value_type *>(data_.get()))) {
334  os<<", data: "<<data_->to_string()
335  <<", count="<<data_.get()->sp_to_string()
336  <<", type: "<<exception_type::thread_traits::demangle_name(typeid(shared_ptr));
337  }
338  return os.str();
339  }
340 
341 } }