Honeycomb  0.1
Component-Model Framework
SharedPtr.h
Go to the documentation of this file.
1 // Honeycomb, Copyright (C) 2015 NewGamePlus Inc. Distributed under the Boost Software License v1.0.
2 #pragma once
3 
4 #include "Honey/Core/Core.h"
5 #include "Honey/Thread/Atomic.h"
6 #include "Honey/Misc/Debug.h"
7 
8 namespace honey
9 {
10 
13 
15 namespace priv
16 {
17  struct SharedObj_tag {};
18 
20  class SharedControl
21  {
22  public:
23  SharedControl() : _count(0), _weakCount(1) {}
24 
26  void ref() { ++_count; }
28  bool refLock() { int old; do { old = _count; if (old <= 0) return false; } while (!_count.cas(old+1,old)); return true; }
30  void unref() { if (--_count > 0) return; finalize(); }
32  int count() const { return _count; }
33 
35  void refWeak() { ++_weakCount; }
37  void unrefWeak() { if (--_weakCount > 0) return; destroy(); }
39  int weakCount() const { return _weakCount; }
40 
41  virtual void finalize() = 0;
42  virtual void destroy() = 0;
43 
44  Atomic<int> _count;
45  Atomic<int> _weakCount;
46  };
47 
49  template<class T, class Fin, class Alloc_>
50  struct SharedControl_ : SharedControl
51  {
52  typedef typename Alloc_::template rebind<SharedControl_>::other Alloc;
53  SharedControl_(T* ptr, Fin&& f, Alloc a) : _ptr(ptr), _fin(forward<Fin>(f)), _alloc(move(a)) {}
54  virtual void finalize() { _fin(_ptr); unrefWeak(); }
55  virtual void destroy() { auto a = move(_alloc); delete_(this, a); }
56 
57  T* _ptr;
58  Fin _fin;
59  Alloc _alloc;
60  };
61 
63  template<class Subclass, class T, bool isIntrusive = mt::is_base_of<SharedObj_tag, T>::value>
64  struct SharedControlPtr
65  {
66  SharedControlPtr() : __control(nullptr) {}
67  SharedControl* _control() const { return __control; }
68  void _control(SharedControl* ptr) { __control = ptr; }
69 
70  SharedControl* __control;
71  };
72 
73  template<class T, class Alloc_> struct SharedControl_obj;
74 }
77 //====================================================
78 // SharedObj
79 //====================================================
80 
82 
92 template<class Subclass>
93 class SharedObj : public priv::SharedObj_tag, mt::NoCopy
94 {
95  template<class, class, bool> friend struct priv::SharedControlPtr;
96  template<class> friend class SharedPtr;
97 
98 public:
100  template<class Alloc = std::allocator<Subclass>>
101  SharedObj(Alloc&& a = Alloc())
102  debug_if(: __control(&_control()))
103  {
104  typedef typename mt::removeRef<Alloc>::type::template rebind<Subclass>::other Alloc_;
105  new (&_controlStorage) Control(subc(), Alloc_(forward<Alloc>(a)));
106  }
107 
108 protected:
110  void finalize() { Control& control = _control(); subc().~Subclass(); control.unrefWeak(); }
111 
112 private:
117  struct Control : priv::SharedControl
118  {
119  template<class Alloc>
120  Control(Subclass& obj, Alloc&& a) : _obj(&obj), _dealloc([=](Subclass* p) mutable { a.deallocate(p,1); }) {}
121 
122  virtual void finalize() { _obj->finalize(); }
123 
124  virtual void destroy()
125  {
126  auto p = _obj;
127  auto dealloc = move(_dealloc);
128  this->~Control();
129  dealloc(p);
130  }
131 
132  Subclass* _obj;
133  function<void (Subclass*)> _dealloc;
134  };
135  typedef typename std::aligned_storage<sizeof(Control), alignof(Control)>::type ControlStorage;
136 
137  Subclass& subc() { return static_cast<Subclass&>(*this); }
138 
139  Control& _control() const { return reinterpret_cast<Control&>(_controlStorage); }
140 
141  mutable ControlStorage _controlStorage;
142  debug_if(Control* __control;) //make control visible in debugger
143 };
144 
146 namespace priv
147 {
149  template<class Subclass, class T>
150  struct SharedControlPtr<Subclass, T, true>
151  {
152  SharedControl* _control() const { return subc()._ptr ? &subc()._ptr->SharedObj::_control() : nullptr; }
153  void _control(SharedControl*) {}
154  private:
155  const Subclass& subc() const { return static_cast<const Subclass&>(*this); }
156  };
157 }
160 //====================================================
161 // SharedPtr
162 //====================================================
163 
164 template<class T, class Fin> class UniquePtr;
165 template<class T> class WeakPtr;
166 
168 
174 template<class T>
175 class SharedPtr : priv::SharedControlPtr<SharedPtr<T>, T>
176 {
177  typedef priv::SharedControlPtr<SharedPtr<T>, T> ControlPtr;
178  friend ControlPtr;
179  template<class> friend class SharedPtr;
180  template<class> friend class WeakPtr;
181  template<class, class> friend struct priv::SharedControl_obj;
182  template<class T_, class U> friend SharedPtr<T_> static_pointer_cast(const SharedPtr<U>&);
183  template<class T_, class U> friend SharedPtr<T_> dynamic_pointer_cast(const SharedPtr<U>&);
184  template<class T_, class U> friend SharedPtr<T_> const_pointer_cast(const SharedPtr<U>&);
185 
186  static const bool isIntrusive = mt::is_base_of<priv::SharedObj_tag, T>::value;
187 
188  template<class T_, bool = std::is_void<T_>::value> struct Ref_ { typedef T_& type; static type deref(T_* p) { return *p; } };
189  template<class T_> struct Ref_<T_, true> { typedef T_ type; static type deref(T_* p) {} };
190 
191 public:
192  typedef T Elem;
193  typedef typename Ref_<Elem>::type Ref;
194 
195  SharedPtr() : _ptr(nullptr) {}
196  SharedPtr(nullptr_t) : _ptr(nullptr) {}
197 
199  template<class U, typename std::enable_if<mt::True<U>::value && isIntrusive, int>::type=0>
200  SharedPtr(U* ptr) : _ptr(nullptr) { set(ptr); }
202 
205  template<class U, class Fin = finalize<U>, class Alloc = typename DefaultAllocator<U>::type, typename mt::disable_if<mt::True<U>::value && isIntrusive, int>::type=0>
206  explicit SharedPtr(U* ptr, Fin&& f = Fin(), Alloc&& a = Alloc()) : _ptr(nullptr) { set(ptr, forward<Fin>(f), forward<Alloc>(a)); }
207 
209  SharedPtr(const SharedPtr& ptr) : _ptr(nullptr) { set(ptr); }
210  template<class U>
211  SharedPtr(const SharedPtr<U>& ptr) : _ptr(nullptr) { set(ptr); }
213  SharedPtr(SharedPtr&& ptr) : _ptr(nullptr) { set(move(ptr)); }
214  template<class U>
215  SharedPtr(SharedPtr<U>&& ptr) : _ptr(nullptr) { set(move(ptr)); }
216 
218  template<class U>
219  explicit SharedPtr(const WeakPtr<U>& ptr) : _ptr(ptr._ptr) { this->_control(ptr._control()); if (_ptr && !getControl().refLock()) _ptr = nullptr; }
220 
222  template<class U, class Fin>
223  SharedPtr(UniquePtr<U,Fin>&& ptr) : _ptr(nullptr) { operator=(move(ptr)); }
224 
225  ~SharedPtr() { set(nullptr); }
226 
227  SharedPtr& operator=(const SharedPtr& rhs) { set(rhs); return *this; }
228  template<class U>
229  SharedPtr& operator=(const SharedPtr<U>& rhs) { set(rhs); return *this; }
230  SharedPtr& operator=(SharedPtr&& rhs) { set(move(rhs)); return *this; }
231  template<class U>
232  SharedPtr& operator=(SharedPtr<U>&& rhs) { set(move(rhs)); return *this; }
233 
234  template<class U, class Fin, typename std::enable_if<mt::True<U>::value && isIntrusive, int>::type=0>
235  SharedPtr& operator=(UniquePtr<U,Fin>&& rhs) { set(rhs.release()); return *this; }
236  template<class U, class Fin, typename mt::disable_if<mt::True<U>::value && isIntrusive, int>::type=0>
237  SharedPtr& operator=(UniquePtr<U,Fin>&& rhs) { set(rhs.release(), move(rhs.finalizer())); return *this; }
238 
239  template<class U>
240  bool operator==(const SharedPtr<U>& rhs) const { return get() == rhs.get(); }
241  template<class U>
242  bool operator!=(const SharedPtr<U>& rhs) const { return !operator==(rhs); }
243  template<class U>
244  bool operator< (const SharedPtr<U>& rhs) const { return std::less<typename std::common_type<T*,U*>::type>()(get(), rhs.get()); }
245  template<class U>
246  bool operator> (const SharedPtr<U>& rhs) const { return rhs.operator<(*this); }
247  template<class U>
248  bool operator<=(const SharedPtr<U>& rhs) const { return !operator>(rhs); }
249  template<class U>
250  bool operator>=(const SharedPtr<U>& rhs) const { return !operator<(rhs); }
251 
252  bool operator==(nullptr_t) const { return !get(); }
253  bool operator!=(nullptr_t) const { return get(); }
254  friend bool operator==(nullptr_t, const SharedPtr& rhs) { return !rhs.get(); }
255  friend bool operator!=(nullptr_t, const SharedPtr& rhs) { return rhs.get(); }
256 
257  T* operator->() const { assert(_ptr); return _ptr; }
258  Ref operator*() const { assert(_ptr); return Ref_<Elem>::deref(_ptr); }
259  operator T*() const { return _ptr; }
260 
262  T* get() const { return _ptr; }
263 
265  template<class U, typename std::enable_if<mt::True<U>::value && isIntrusive, int>::type=0>
266  void set(U* ptr) { setControl(ptr, ptr ? &ptr->SharedObj::_control() : nullptr); }
268  template<class U, class Fin = finalize<U>, class Alloc = typename DefaultAllocator<U>::type, typename mt::disable_if<mt::True<U>::value && isIntrusive, int>::type=0>
269  void set(U* ptr, Fin&& f = Fin(), Alloc&& a = Alloc())
270  {
271  typedef priv::SharedControl_<U,Fin,Alloc> Control;
272  typedef typename Alloc::template rebind<Control>::other Alloc_;
273  Alloc_ a_ = forward<Alloc>(a);
274  setControl(ptr, ptr ? new (a_.allocate(1)) Control(ptr, forward<Fin>(f), move(a_)) : nullptr);
275  }
276  void set(nullptr_t) { set((T*)nullptr); }
277 
279  int refCount() const { if (_ptr) return getControl().count(); return 0; }
281  bool unique() const { return refCount() == 1; }
282 
283 private:
284  template<class U> void set(const SharedPtr<U>& rhs) { setControl(rhs._ptr, rhs._control()); }
285  template<class U> void set(SharedPtr<U>&& rhs) { moveControl(rhs._ptr, rhs._control()); rhs._ptr = nullptr; rhs._control(nullptr); }
286 
287  template<class U>
288  void setControl(U* ptr, priv::SharedControl* control)
289  {
290  if (ptr) control->ref();
291  T* oldPtr = _ptr; priv::SharedControl* oldControl = this->_control();
292  _ptr = ptr; this->_control(control);
293  if (oldPtr) oldControl->unref();
294  }
295 
296  template<class U>
297  void moveControl(U* ptr, priv::SharedControl* control)
298  {
299  if (_ptr && this->_control() != control)
300  this->_control()->unref();
301  _ptr = ptr; this->_control(control);
302  }
303 
304  priv::SharedControl& getControl() const { assert(this->_control()); return *this->_control(); }
305 
306  T* _ptr;
307 };
308 
310 namespace priv
311 {
313  template<class T, class Alloc_>
314  struct SharedControl_obj : SharedControl
315  {
316  typedef typename mt::removeRef<Alloc_>::type::template rebind<SharedControl_obj>::other Alloc;
317  typedef typename std::aligned_storage<sizeof(T), alignof(T)>::type Storage;
318 
319  template<class... Args>
320  static SharedPtr<T> create(Alloc a, Args&&... args)
321  {
322  auto* control = new (a.allocate(1)) SharedControl_obj(move(a), forward<Args>(args)...);
323  SharedPtr<T> ptr;
324  ptr.setControl(&control->_obj(), control);
325  return ptr;
326  }
327 
328  template<class... Args>
329  SharedControl_obj(Alloc&& a, Args&&... args) : _alloc(move(a)) { new (&_storage) T(forward<Args>(args)...); }
330  virtual void finalize() { _obj().~T(); unrefWeak(); }
331  virtual void destroy() { auto a = move(_alloc); delete_(this, a); }
332  T& _obj() { return reinterpret_cast<T&>(_storage); }
333 
334  Storage _storage;
335  Alloc _alloc;
336  };
337 }
340 
342 template<class T, class Alloc, class... Args, typename mt::disable_if<mt::is_base_of<priv::SharedObj_tag, T>::value, int>::type=0>
343 SharedPtr<T> alloc_shared(Alloc&& a, Args&&... args) { return priv::SharedControl_obj<T,Alloc>::create(forward<Alloc>(a), forward<Args>(args)...); }
345 
346 template<class T, class Alloc, class... Args, typename std::enable_if<mt::is_base_of<priv::SharedObj_tag, T>::value, int>::type=0>
347 SharedPtr<T> alloc_shared(Alloc&& a, Args&&... args) { return SharedPtr<T>(new (a.allocate(1)) T(forward<Args>(args)...)); }
349 
350 template<class T, class... Args, class Alloc = typename DefaultAllocator<T>::type>
351 SharedPtr<T> make_shared(Args&&... args) { return alloc_shared<T>(Alloc(), forward<Args>(args)...); }
352 
354 template<class T, class U>
355 SharedPtr<T> static_pointer_cast(const SharedPtr<U>& rhs) { SharedPtr<T> ret; ret.setControl(static_cast<T*>(rhs._ptr), rhs._control()); return ret; }
357 template<class T, class U>
358 SharedPtr<T> dynamic_pointer_cast(const SharedPtr<U>& rhs) { SharedPtr<T> ret; ret.setControl(dynamic_cast<T*>(rhs._ptr), rhs._control()); return ret; }
360 template<class T, class U>
361 SharedPtr<T> const_pointer_cast(const SharedPtr<U>& rhs) { SharedPtr<T> ret; ret.setControl(const_cast<T*>(rhs._ptr), rhs._control()); return ret; }
362 
363 //====================================================
364 // WeakPtr
365 //====================================================
366 
368 
376 template<class T>
377 class WeakPtr : priv::SharedControlPtr<WeakPtr<T>, T>
378 {
379  typedef priv::SharedControlPtr<WeakPtr<T>, T> ControlPtr;
380  friend ControlPtr;
381  template<class> friend class WeakPtr;
382  template<class> friend class SharedPtr;
383 
384 public:
385  WeakPtr() : _ptr(nullptr) {}
386  WeakPtr(nullptr_t) : _ptr(nullptr) {}
388  template<class U>
389  WeakPtr(const SharedPtr<U>& rhs) : _ptr(nullptr) { operator=(rhs); }
390  WeakPtr(const WeakPtr& rhs) : _ptr(nullptr) { operator=(rhs); }
391  template<class U>
392  WeakPtr(const WeakPtr<U>& rhs) : _ptr(nullptr) { operator=(rhs); }
393 
394  ~WeakPtr() { if (_ptr) getControl().unrefWeak(); }
395 
396  WeakPtr& operator=(const WeakPtr& rhs) { setControl(rhs._ptr, rhs._control()); return *this; }
397  template<class U>
398  WeakPtr& operator=(const WeakPtr<U>& rhs) { setControl(rhs._ptr, rhs._control()); return *this; }
399  template<class U>
400  WeakPtr& operator=(const SharedPtr<U>& rhs) { setControl(rhs._ptr, rhs._control()); return *this; }
401 
403  void set(nullptr_t) { setControl(static_cast<T*>(nullptr), nullptr); }
404 
406  SharedPtr<T> lock() const { return SharedPtr<T>(*this); }
407 
409  int refCount() const { if (_ptr) return getControl().count(); return 0; }
411  bool expired() const { return refCount() == 0; }
412 
413 private:
414  template<class U>
415  void setControl(U* ptr, priv::SharedControl* control)
416  {
417  if (ptr) control->refWeak();
418  T* oldPtr = _ptr; priv::SharedControl* oldControl = this->_control();
419  _ptr = ptr; this->_control(control);
420  if (oldPtr) oldControl->unrefWeak();
421  }
422 
423  priv::SharedControl& getControl() const { assert(this->_control()); return *this->_control(); }
424 
425  T* _ptr;
426 };
427 
429 
430 }
431 
432 namespace std
433 {
435  template<class T>
436  struct hash<honey::SharedPtr<T>>
437  {
438  size_t operator()(const honey::SharedPtr<T>& val) const { return reinterpret_cast<size_t>(val.get()); };
439  };
440 }
~SharedPtr()
Definition: SharedPtr.h:225
SharedPtr< T > dynamic_pointer_cast(const SharedPtr< U > &rhs)
Definition: SharedPtr.h:358
SharedPtr(SharedPtr &&ptr)
Transfer ownership out of shared pointer, leaving it null.
Definition: SharedPtr.h:213
void set(nullptr_t)
Set to null, release reference.
Definition: SharedPtr.h:403
WeakPtr()
Definition: SharedPtr.h:385
Version of std::is_base_of that removes reference qualifiers before testing.
Definition: Meta.h:69
WeakPtr & operator=(const SharedPtr< U > &rhs)
Definition: SharedPtr.h:400
friend bool operator!=(nullptr_t, const SharedPtr &rhs)
Definition: SharedPtr.h:255
bool operator>(const String &lhs, const String &rhs)
Definition: String.h:148
Combined intrusive/non-intrusive smart pointer. Can reference and share any object automatically...
Definition: SharedPtr.h:175
void set(nullptr_t)
Definition: SharedPtr.h:276
bool operator!=(nullptr_t) const
Definition: SharedPtr.h:253
SharedPtr(const SharedPtr &ptr)
Reference the object pointed to by another shared pointer.
Definition: SharedPtr.h:209
Ref_< Elem >::type Ref
Definition: SharedPtr.h:193
Inherit to declare that class is not copyable.
Definition: Meta.h:286
SharedPtr< T > const_pointer_cast(const SharedPtr< U > &rhs)
Definition: SharedPtr.h:361
SharedPtr< T > lock() const
Acquire access to object. Shared ptr prevents object from being destroyed while in use...
Definition: SharedPtr.h:406
void delete_(T *&p)
Destruct object, free memory and set pointer to null.
Definition: Allocator.h:75
STL namespace.
~WeakPtr()
Definition: SharedPtr.h:394
SharedPtr< T > alloc_shared(Alloc &&a, Args &&...args)
Create a shared ptr to an object of type T constructed with args. The object and the internal control...
Definition: SharedPtr.h:343
int refCount() const
Get number of shared references to the object.
Definition: SharedPtr.h:279
SharedPtr(SharedPtr< U > &&ptr)
Definition: SharedPtr.h:215
T * get() const
Get the raw pointer to the object.
Definition: SharedPtr.h:262
size_t operator()(const honey::SharedPtr< T > &val) const
Definition: SharedPtr.h:438
Reference-counted object for intrusive shared pointers.
Definition: SharedPtr.h:93
std::remove_reference< T > removeRef
Remove reference from type.
Definition: Meta.h:44
SharedPtr & operator=(SharedPtr &&rhs)
Definition: SharedPtr.h:230
Ref operator*() const
Definition: SharedPtr.h:258
SharedPtr< T > static_pointer_cast(const SharedPtr< U > &rhs)
Definition: SharedPtr.h:355
bool unique() const
Check whether this is the only shared reference to the object.
Definition: SharedPtr.h:281
bool operator<(const String &lhs, const String &rhs)
Definition: String.h:145
SharedPtr(UniquePtr< U, Fin > &&ptr)
Transfer ownership out of unique pointer, leaving it null.
Definition: SharedPtr.h:223
WeakPtr(const WeakPtr &rhs)
Definition: SharedPtr.h:390
SharedPtr< T > alloc_shared(Alloc &&a, Args &&...args)
Specializaton for intrusive pointers, simply allocates T and constructs with args.
Definition: SharedPtr.h:347
SharedPtr(U *ptr, Fin &&f=Fin(), Alloc &&a=Alloc())
Reference an object with finalizer and internal control block allocator. For non-intrusive pointers o...
Definition: SharedPtr.h:206
bool expired() const
Check whether the object has already been destroyed.
Definition: SharedPtr.h:411
T Elem
Definition: SharedPtr.h:192
#define assert(...)
Forwards to assert_#args. See assert_1(), assert_2().
Definition: Debug.h:24
std::enable_if< std::is_default_constructible< Com >::value &&!std::is_abstract< Com >::value, Component & >::type create()
Called by registry to create a component. May be specialized for a component type.
Definition: Component.h:75
SharedObj(Alloc &&a=Alloc()) debug_if(
Construct with allocator that is called to deallocate this shared object when all references have bee...
Definition: SharedPtr.h:101
SharedPtr(const SharedPtr< U > &ptr)
Definition: SharedPtr.h:211
int refCount() const
Get strong reference (SharedPtr) count.
Definition: SharedPtr.h:409
bool operator!=(const SharedPtr< U > &rhs) const
Definition: SharedPtr.h:242
SharedPtr & operator=(const SharedPtr< U > &rhs)
Definition: SharedPtr.h:229
SharedPtr(const WeakPtr< U > &ptr)
Lock a weak pointer to get access to its object. Shared ptr will be null if the object has already be...
Definition: SharedPtr.h:219
T * operator->() const
Definition: SharedPtr.h:257
#define debug_if(...)
Evaluate expression in debug mode only, does nothing in final mode.
Definition: Debug.h:30
void finalize()
Destroys object. Called when strong reference count reaches 0. May be overridden to prevent destructi...
Definition: SharedPtr.h:110
WeakPtr & operator=(const WeakPtr< U > &rhs)
Definition: SharedPtr.h:398
SharedPtr< T > make_shared(Args &&...args)
alloc_shared() using T::Allocator if available, otherwise std::allocator
Definition: SharedPtr.h:351
SharedPtr & operator=(const SharedPtr &rhs)
Definition: SharedPtr.h:227
NoCopy & operator=(const NoCopy &)=delete
SharedPtr & operator=(SharedPtr< U > &&rhs)
Definition: SharedPtr.h:232
WeakPtr & operator=(const WeakPtr &rhs)
Definition: SharedPtr.h:396
bool operator==(const String &lhs, const String &rhs)
Definition: String.h:139
friend bool operator==(nullptr_t, const SharedPtr &rhs)
Definition: SharedPtr.h:254
SharedPtr & operator=(UniquePtr< U, Fin > &&rhs)
Definition: SharedPtr.h:235
bool operator==(nullptr_t) const
Definition: SharedPtr.h:252
WeakPtr(const SharedPtr< U > &rhs)
Must construct from a shared pointer.
Definition: SharedPtr.h:389
bool operator>=(const SharedPtr< U > &rhs) const
Definition: SharedPtr.h:250
Point to a shared object without holding a reference. The object is accessible through a lock...
Definition: SharedPtr.h:165
void set(U *ptr, Fin &&f=Fin(), Alloc &&a=Alloc())
Dereference the current object and reference a new object, with finalizer and internal control block ...
Definition: SharedPtr.h:269
SharedPtr()
Definition: SharedPtr.h:195
Pointer to a unique, non-shared, object. Finalizer is run upon destruction (deletes object by default...
Definition: SharedPtr.h:164
WeakPtr(const WeakPtr< U > &rhs)
Definition: SharedPtr.h:392
WeakPtr(nullptr_t)
Definition: SharedPtr.h:386
SharedPtr(nullptr_t)
Definition: SharedPtr.h:196
std::allocator< T > type
Definition: Allocator.h:152
Global Honeycomb namespace.
void set(U *ptr)
Dereference the current object and reference a new object. For intrusive pointers only...
Definition: SharedPtr.h:266
SharedPtr(U *ptr)
Reference an object, allowing for implicit construction. For intrusive pointers only.
Definition: SharedPtr.h:200
bool operator==(const SharedPtr< U > &rhs) const
Definition: SharedPtr.h:240