Handle.hpp
1 #pragma once
2 
3 //stl
4 #include <atomic>
5 #include <type_traits>
6 #include <limits>
7 
8 #include <assert.h>
9 //PA
10 #include "DM/config.hpp"
11 #include "DM/ObjectBaseRefCounting.hpp"
12 
13 //NG
14 #include "NG_Exception.hpp"
15 
16 DM_NAMESPACE_BEGIN
17 
18 DM_API void *allocate_internal(size_t); //allocates memory inside DM heap
19 DM_API void deallocate_internal(void *); //frees allocated memory from the DM heap
20 
21 /**
22  \brief Allocator template class using new/delete
23  \author JO
24  \date 07.04.2005
25  \see PH_malloc_allocator
26 
27  The allocator class can be used in PH_List, PH_listOld, PH_vector and its
28  super classes as memory manager. The class uses new and delete for managing
29  the memory. The code is based on the Boost Library http://www.boost.org/
30 */
31 template <typename T>
32 struct DM_API Default_allocator
33 {
34  typedef T * pointer;
35  typedef const T * const_pointer;
36  typedef T & reference;
37  typedef const T & const_reference;
38  typedef T value_type;
39 
40  typedef std::size_t size_type;
41  typedef std::ptrdiff_t difference_type;
42 
43  template <typename U>
44  struct rebind
45  {
47  };
48 
49  static pointer address(reference r) { return &r; }
50  static const_pointer address(const_reference r) { return &r; }
51 
52  static pointer allocate(const size_type n, const pointer = 0)
53  { return (pointer)allocate_internal(n * sizeof(T)); }
54 
55  static void deallocate(const pointer p, const size_type)
56  { deallocate_internal((char *)p); }
57  static size_type max_size() { return (std::numeric_limits<size_type>::max)(); }
58 
59  bool operator==(const Default_allocator &) const { return true; }
60  bool operator!=(const Default_allocator &) const { return false; }
61 
62  Default_allocator() { }
63  template <typename U>
64  Default_allocator(const Default_allocator<U> &) { }
65 
66  static void construct(const pointer p, const_reference t)
67  { new ((void *) p) T(t); }
68  static void destroy(const pointer p)
69  { p->~T(); }
70 };
71 
72 
73 /// \brief Smart pointer class using reference counting with support for DM objects (see ObjectBase)
74 template <class T, bool Thread_safe = true, class C = unsigned int, class Alloc = Default_allocator<T> >
75 class Handle
76 {
77  template<bool Tb>
78  struct bool_tag { typedef std::integral_constant<bool,Tb> type; };
79 
80  /// the notify struct is used to communicate the reference conuter to the object it self (of derived from ObjectBaseRefCounting)
81  template<typename AnyT, class CC = unsigned int>
82  struct notify {
83  //non notifying
84  inline CC inc(T *t, CC count) const { return count; }
85  inline CC dec(T *t, CC count) const { return count; }
86  };
87  template<class CC>
88  struct notify<std::true_type,CC> {
89  //notifying template specialization
90  inline CC inc(T *t, CC count) const { static_cast<ObjectBaseRefCounting *>(t)->refAdded(count); return count; }
91  inline CC dec(T *t, CC count) const { static_cast<ObjectBaseRefCounting *>(t)->refRemoved(count); return count; }
92  };
93 
94 
95  template<class TT, bool Thread_safe_, class CC = unsigned int>
96  struct RefCountedT {
97  typedef notify< typename std::is_base_of<ObjectBaseRefCounting, typename std::remove_pointer<T>::type >::type, CC> notify_type;
98 
99  inline CC increaseCount() { return notify_type().inc( t, ++count ); }
100  inline CC decreaseCount() { return notify_type().dec( t, --count ); }
101  inline CC getCount() const { return static_cast<CC const volatile &>( count ); }
102 
103  TT t;
104  std::atomic<CC> count;
105  };
106  /// Non-thread safe specialisation
107  template<class TT, class CC>
108  struct RefCountedT<TT, false, CC > {
109  typedef notify< typename std::is_base_of<ObjectBaseRefCounting, typename std::remove_pointer<TT>::type >::type, CC> notify_type;
110 
111  inline CC increaseCount() { return notify_type().inc( t, ++count); }
112  inline CC decreaseCount() { return notify_type().dec( t, --count); }
113  inline CC getCount() const { return count; }
114 
115  TT t;
116  CC count;
117  };
118 
119 
120  typedef RefCountedT<T *, Thread_safe, C> RefCounted;
121  typedef typename Alloc::template rebind< RefCounted >::other Allocator;
122  typedef typename Allocator::pointer pointer;
123 
124  static Allocator allocator;
125  pointer ptr_;
126 
128 
129 
130  void Delete(std::false_type& isScalar, T *&t) {
131  t->Delete();
132  }
133  void Delete(std::true_type& isScalar, T *&t) {
134  throw NG_exception("scalar types are not suited for this Handle class, since the do not provide a Delete function");
135  //delete t;
136  }
137 
138 public:
139  typedef T element_type;
140 
141  struct use_dynamic_cast {};
142  struct use_static_cast {};
143 
144  Handle() : ptr_(0)
145  {
146  }
147 
148  Handle(const Handle& h)
149  : ptr_(h.ptr_)
150  {
151  if (ptr_)
152  {
153  assert( (ptr_->count) < (std::numeric_limits<C>::max)() );
154  ptr_->increaseCount();
155  }
156  }
157 
158  template<class T2, bool TS2, class C2, class A2>
159  Handle(const Handle<T2, TS2, C2, A2> &other) : ptr_(0)
160  {
161  if (other.ptr_)
162  {
163  ptr_ = do_static_cast<T2, TS2, C2, A2,
164  typename std::is_base_of<T, T2>::type,
165  typename std::is_same<bool_tag<Thread_safe>, bool_tag<TS2>>::type,
166  typename std::is_same<Allocator, typename A2::template rebind< RefCounted >::other>::type >()(other.ptr_);
167  assert( (ptr_->count) < (std::numeric_limits<C>::max)() );
168  ptr_->increaseCount();
169  }
170  }
171 
172  template<class T2, bool TS2, class C2, class A2>
173  Handle(const Handle<T2, TS2, C2, A2> &other, const use_static_cast &) : ptr_(0)
174  {
175  if (other.ptr_)
176  {
177  ptr_ = do_static_cast<T2, TS2, C2, A2,
178  typename std::true_type,
179  typename std::is_same<bool_tag<Thread_safe>, bool_tag<TS2>>::type,
180  typename std::is_same<Allocator, typename A2::template rebind< RefCounted >::other>::type >()(other.ptr_);
181  assert( (ptr_->count) < (std::numeric_limits<C>::max)() );
182  ptr_->increaseCount();
183  }
184  }
185 
186  template<class T2, bool TS2, class C2, class A2>
187  Handle(const Handle<T2, TS2, C2, A2> &other, const use_dynamic_cast &) : ptr_(0)
188  {
189  if (other.ptr_)
190  {
191  ptr_ = do_dynamic_cast<T2, TS2, C2, A2,
192  typename std::is_same<bool_tag<Thread_safe>, bool_tag<TS2>>::type,
193  typename std::is_same<Allocator, typename A2::template rebind< RefCounted >::other>::type >()(other.ptr_);
194  if (ptr_)
195  {
196  assert( (ptr_->count) < (std::numeric_limits<C>::max)() );
197  ptr_->increaseCount();
198  }
199  }
200  }
201 
202  Handle(T* p) : ptr_(0)
203  {
204  if (p)
205  {
206  ptr_ = (allocator.allocate(1));
207  ptr_->t = p;
208  ptr_->count = 1;
209  }
210  }
211 
212 
213 
214  ~Handle()
215  {
216  if (ptr_)
217  {
218  if (ptr_->decreaseCount() == 0 )
219  {
220  //delete ptr_->t;
221  typename std::is_scalar<T>::type type;
222  Delete( type, ptr_->t );
223  allocator.destroy( ptr_);
224  allocator.deallocate( ptr_, 1);
225  }
226  }
227  }
228 
229  Handle& operator=(const Handle& h)
230  {
231  Handle tmp = h;
232  swap(tmp);
233  return *this;
234  }
235 
236  template<class T2, bool TS2, class C2, class A2>
237  Handle& operator=(const Handle<T2, TS2, C2, A2> &other)
238  {
239  Handle tmp = other;
240  swap(tmp);
241  return *this;
242  }
243 
244  Handle&
245  operator=(T *p)
246  {
247  *this = Handle(p);
248  return *this;
249  }
250 
251  size_type
252  id() const
253  { return reinterpret_cast<size_type>(&*ptr_); }
254 
255  /*void create_from_id(size_type id)
256  {
257  Handle tmp;
258  tmp.ptr_ = reinterpret_cast<RefCounted *>(id);
259  tmp.ptr_->increaseCount();
260  swap(tmp);
261  }*/
262 
263  operator const T &() const {
264  return *(ptr_->t);
265  }
266 
267  operator T &() {
268  return *(ptr_->t);
269  }
270 
271  const T *ptr() const
272  {
273  return (ptr_) ? ptr_->t : 0;
274  }
275 
276  const T & operator*() const { return *(ptr_->t); }
277  T & operator*() { return *(ptr_->t); }
278  const T * operator->() const { return (ptr_) ? ptr_->t : 0; }
279  T * operator->() { return (ptr_) ? ptr_->t : 0; }
280 
281  bool is_shared() const
282  {
283  return (ptr_ && ptr_->count > 1);
284  }
285 
286  C get_count() const
287  {
288  return (ptr_ ? ptr_->getCount() : 0);
289  }
290 
291  T *release()
292  {
293  if( ptr_ )
294  {
295  if (ptr_->decreaseCount() != 0)
296  throw NG_exception("Shared objects (reference counter > 1) cannot be released");
297 
298  T *p = ptr_->t;
299  allocator.destroy( ptr_);
300  allocator.deallocate( ptr_, 1);
301  ptr_ = 0;
302  return p;
303  }
304  return 0;
305  }
306 
307  void swap(Handle& h)
308  {
309  std::swap(ptr_, h.ptr_);
310  }
311 
312  void reset() {
313  Handle h = Handle();
314  swap( h );
315  }
316 
317  Handle clone() const
318  {
319  return (ptr_ ? Handle( ptr_->t->clone() ) : Handle() );
320  }
321 
322  bool operator==(const Handle& h) const
323  {
324  return (ptr_ == h.ptr_);
325  }
326 
327  bool operator!=(const Handle& h) const
328  {
329  return (ptr_ != h.ptr_);
330  }
331 
332  bool operator>(const Handle& h) const
333  {
334  return (ptr_ > h.ptr_);
335  }
336 
337  bool operator<(const Handle& h) const
338  {
339  return (ptr_ < h.ptr_);
340  }
341 
342  typedef const T * (self::*unspecified_bool_type)() const;
343 
344  operator unspecified_bool_type() const
345  {
346  return ptr_ == 0
347  ? 0
348  : &self::ptr;
349  }
350 
351 protected:
352 
353  template<typename T2, bool TS2, class C2, class A2, typename BaseFlag, typename SameThreadFlag, typename SameAllocFlag>
354  struct do_static_cast {
355  RefCounted * operator()(const typename Handle<T2, TS2, C2, A2>::RefCounted *ptr) {
356  static_assert(sizeof(ptr)==0); //if you get an error here, an illegale handle conversion was tried to perfom:
357  //possible reasons:
358  // * Thread_flag is different
359  // * C type (reference counter) is different
360  // * Allocator type is different
361 
362  return 0;
363  }
364  };
365 
366  template<typename T2, bool TS2, class A2>
367  struct do_static_cast<T2, TS2, C, A2, std::false_type, std::true_type, std::true_type> {
368  RefCounted * operator()(const typename Handle<T2, TS2, C, A2>::RefCounted *ptr) {
369  static_assert(sizeof(ptr)==0); //if you get an error here, an illegale cast was tried to perfom:
370  //T is not a base T2. You may try to use the "use_static_cast constructor"
371 
372  return 0;
373  }
374  };
375 
376  template<typename T2, bool TS2, class A2>
377  struct do_static_cast<T2, TS2, C, A2, std::true_type, std::true_type, std::true_type> {
378  RefCounted * operator()(const typename Handle<T2, TS2, C, A2>::RefCounted *ptr) {
379  return (RefCounted *)((void *)(ptr));
380  }
381  };
382 
383 
384 
385 
386  template<typename T2, bool TS2, class C2, class A2, typename SameThreadFlag, typename SameAllocFlag>
388  RefCounted * operator()(const typename Handle<T2, TS2, C2, A2>::RefCounted *ptr) {
389  static_assert(sizeof(ptr)==0); //if you get an error here, an illegale handle conversion was tried to perfom:
390  //possible reasons:
391  // * Thread_flag is different
392  // * C type (reference counter) is different
393  // * Allocator type is different
394 
395  return 0;
396  }
397  };
398 
399  template<typename T2, bool TS2, class A2>
400  struct do_dynamic_cast<T2, TS2, C, A2, std::true_type, std::true_type> {
401  RefCounted * operator()(const typename Handle<T2, TS2, C, A2>::RefCounted *ptr) {
402  T *p = dynamic_cast<T*>(ptr->t);
403  if (p)
404  return (RefCounted *)((void *)(ptr));
405  else
406  return 0;
407  }
408  };
409 
410 
411  template<class T2, bool TT2, class C2, class A2>
412  friend class Handle;
413 };
414 
415 
416 template <class T, bool TT, class C, class Allocator>
417 typename Handle<T, TT, C, Allocator>::Allocator
419 
420 template <class T, bool TT, class C, class Allocator>
422 {
423  h1.swap(h2);
424 }
425 
426 template <class T>
428 {
429  typedef StaticHandle<T> self;
430 
431  typedef T* pointer;
432  pointer ptr_;
433 
434 public:
435  typedef T element_type;
436 
437  struct use_dynamic_cast {};
438  struct use_static_cast {};
439 
440  StaticHandle() : ptr_(0)
441  {
442  }
443 
444  StaticHandle(const StaticHandle& h)
445  : ptr_(h.ptr_)
446  {
447  }
448 
449  template<class T2>
450  StaticHandle(const StaticHandle<T2> &other) : ptr_(0)
451  {
452  if (other.ptr_)
453  {
454  ptr_ = do_static_cast<T2, typename std::is_base_of<T, T2>::type >()(other.ptr_);
455  }
456  }
457 
458  template<class T2>
459  StaticHandle(const StaticHandle<T2> &other, const use_static_cast &) : ptr_(0)
460  {
461  if (other.ptr_)
462  {
463  ptr_ = do_static_cast<T2, std::true_type >()(other.ptr_);
464  }
465  }
466 
467  template<class T2>
468  StaticHandle(const StaticHandle<T2> &other, const use_dynamic_cast &) : ptr_(0)
469  {
470  if (other.ptr_)
471  {
472  ptr_ = do_dynamic_cast<T2>()(other.ptr_);
473  }
474  }
475 
476  StaticHandle(T* p) : ptr_(p)
477  {
478  }
479 
480  ~StaticHandle()
481  {
482  }
483 
484  StaticHandle& operator=(const StaticHandle& h)
485  {
486  ptr_ = h.ptr_;
487  return *this;
488  }
489 
490  template<class T2>
491  StaticHandle& operator=(const StaticHandle<T2> &other)
492  {
493  StaticHandle tmp = other;
494  ptr_ = tmp.ptr_;
495  return *this;
496  }
497 
498  StaticHandle&
499  operator=(T *p)
500  {
501  ptr_ = p;
502  return *this;
503  }
504 
505  size_type
506  id() const
507  { return reinterpret_cast<size_type>(ptr_); }
508 
509  operator const T &() const {
510  return *(ptr_);
511  }
512 
513  const T *ptr() const
514  {
515  return (ptr_);
516  }
517 
518  T &operator*() const { return *(ptr_); }
519  T *operator->() const { return (ptr_); }
520 
521  /*bool is_shared() const
522  {
523  return (ptr_ && ptr_->count > 1);
524  }
525 
526  C get_count() const
527  {
528  return (ptr_ ? ptr_->getCount() : 0);
529  }*/
530 
531  void swap(StaticHandle& h)
532  {
533  std::swap(ptr_, h.ptr_);
534  }
535 
536  void reset() {
537  ptr_ = (T *)0;
538  }
539 
540  StaticHandle clone() const
541  {
542  return StaticHandle(ptr_);
543  }
544 
545  bool operator==(const StaticHandle& h) const
546  {
547  return (ptr_ == h.ptr_);
548  }
549 
550  bool operator!=(const StaticHandle& h) const
551  {
552  return (ptr_ != h.ptr_);
553  }
554 
555  bool operator>(const StaticHandle& h) const
556  {
557  return (ptr_ > h.ptr_);
558  }
559 
560  bool operator<(const StaticHandle& h) const
561  {
562  return (ptr_ < h.ptr_);
563  }
564 
565  operator bool() const
566  {
567  return ptr_ != (T *)0;
568  }
569 
570 protected:
571 
572  template<typename T2, typename TagT>
573  struct do_static_cast {
574  pointer operator()(const typename StaticHandle<T2>::pointer *ptr) {
575  static_assert(sizeof(ptr)==0); //if you get an error here, an illegale cast was tried to perfom:
576  //T is not a base T2. You may try to use the "use_static_cast constructor"
577  return 0;
578  }
579  };
580 
581  template<typename T2>
582  struct do_static_cast<T2, std::true_type> {
583  pointer operator()(const typename StaticHandle<T2>::pointer *ptr) {
584  return (pointer)(ptr);
585  }
586  };
587 
588  template<typename T2>
590  pointer operator()(const typename StaticHandle<T2>::pointer *ptr) {
591  return dynamic_cast<pointer>(ptr);
592  }
593  };
594 
595 
596  template<class T2>
597  friend class StaticHandle;
598 };
599 
600 
601 
602 DM_NAMESPACE_END
Definition: Handle.hpp:142
Definition: ObjectBaseRefCounting.hpp:9
Definition: Handle.hpp:437
Exception wrapper.
Definition: NG_Exception.hpp:13
Definition: Handle.hpp:44
Definition: Handle.hpp:589
Definition: Handle.hpp:438
Definition: Handle.hpp:427
Definition: Handle.hpp:141
Definition: Handle.hpp:573
Allocator template class using new/delete.
Definition: Handle.hpp:32
Definition: Handle.hpp:387
@ count
always last element
Smart pointer class using reference counting with support for DM objects (see ObjectBase)
Definition: Handle.hpp:75
Definition: Handle.hpp:354