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