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