cgv
ref_ptr.h
1 #pragma once
2 
3 #include "ref_counted.h"
4 
5 #include <cgv/defines/assert.h>
6 #include <cgv/type/cond/is_base_of.h>
7 #include <cgv/type/cond/has_virtual_destructor.h>
8 #include <assert.h>
9 
10 #include "lib_begin.h"
11 
12 namespace cgv {
14  namespace data {
15 
16 // extern CGV_API bool validate_delete(const void* ptr);
17 
18 template <class T, bool is_ref_counted>
19 class ref_ptr;
20 
23 {
24 protected:
26  void inc_ref_count(const ref_counted* ptr) const
27  {
28  ptr->set_ref_count(ptr->get_ref_count()+1);
29  }
31  bool dec_ref_count(const ref_counted* ptr) const
32  {
33  int count = ptr->get_ref_count();
34  if (count > 0) {
35  ptr->set_ref_count(count-1);
36  return count == 1;
37  }
38  // ERROR: zero ref count decremented
39  assert(0);
40  return false;
41  }
42 };
43 
44 template <typename T, bool is_ref_counted = false>
45 class ref_ptr_impl
46 {
47 protected:
48  friend class ref_ptr_impl<const T, is_ref_counted>;
50  struct counter_type
51  {
52  counter_type(T* p, int c) : ptr(p), count(c) {}
53  T* ptr;
54  int count;
55  };
57  mutable counter_type* counter;
59  void release()
60  {
61  if (counter) {
62  if (--counter->count == 0) {
63  delete counter->ptr;
64  counter->ptr = 0;
65  delete counter;
66  }
67  counter = 0;
68  }
69  }
71  T* ref () const { return counter ? counter->ptr : 0; }
73  explicit ref_ptr_impl(T* p = 0) : counter(0) {
74  if (p)
75  counter = new counter_type(p, 1);
76  }
78  ref_ptr_impl(const ref_ptr_impl<T,false>& r) : counter(r.counter)
79  {
80  if (counter)
81  ++counter->count;
82  }
84  template <typename S>
85  ref_ptr_impl(const ref_ptr_impl<S,false>& s)
86  {
87  // ref_ptr conversion only valid if T is base of S
88  CGV_DEFINES_ASSERT(type::cond::is_base_of<T,S>::value);
89  // and T has a virtual destructor
90  CGV_DEFINES_ASSERT(type::cond::has_virtual_destructor<T>::value);
91  // after validity checks, set pointer
92  counter = reinterpret_cast<counter_type*>(s.counter);
93  // and increment reference count
94  if (counter)
95  ++counter->count;
96  }
97 public:
99  int get_count() const { return counter ? counter->count : 0; }
100 };
101 
102 template <typename T>
103 class ref_ptr_impl<T,true> : public ref_ptr_tag
104 {
105  T* ptr;
106 protected:
108  void release() {
109  if (ptr) {
110  if (dec_ref_count(ptr)) {
111 // if (validate_delete(ptr))
112  delete ptr;
113  }
114  ptr = 0;
115  }
116  }
118  T* ref () const {
119  return ptr;
120  }
122  explicit ref_ptr_impl(T* p) : ptr(p) {
123  if (ptr)
124  inc_ref_count(ptr);
125  }
127  ref_ptr_impl(const ref_ptr_impl<T,true>& r) : ptr(r.ref())
128  {
129  if (ptr)
130  inc_ref_count(ptr);
131  }
133  template <typename S>
134  ref_ptr_impl(const ref_ptr_impl<S,true>& s)
135  {
136  // ref_ptr conversion only valid if T is base of S
137  CGV_DEFINES_ASSERT(type::cond::is_base_of<T,S>::value);
138  // and T has a virtual destructor
139  CGV_DEFINES_ASSERT(type::cond::has_virtual_destructor<T>::value);
140  // after validity checks, set pointer with a very bad hack!!
141  ptr = static_cast<const ref_ptr<S,true>&>(s).operator->();
142  // and increment reference count
143  if (ptr)
144  inc_ref_count(ptr);
145  }
146 public:
147  // void kill() { ptr = 0; }
149  int get_count() const {
150  return ptr ? ptr->get_ref_count() : 0;
151  }
152 };
153 
158 template <class T, bool is_ref_counted = type::cond::is_base_of<ref_counted,T>::value>
159 class ref_ptr : public ref_ptr_impl<T,is_ref_counted>
160 {
161 public:
165  typedef ref_ptr_impl<T,is_ref_counted> base_type;
166 public:
168  ref_ptr(T* p = 0) : base_type(p) {}
170  ref_ptr(const this_type& r) : base_type(r) {}
172  ~ref_ptr() {
173  this->release();
174  }
176  template <typename S>
179  template <typename S>
181  // ref_ptr conversion only valid if T is base of S
182  CGV_DEFINES_ASSERT(type::cond::is_base_of<T,S>::value);
183  // and S has a virtual destructor
185  // after validity checks, return converted pointer
187  *reinterpret_cast<const ref_ptr<S,is_ref_counted>*>(this)
188  );
189  }
192  if (this == &r)
193  return *this;
194  this->release();
195  new (this) this_type(r);
196  return *this;
197  }
199  template <typename S>
201  if (this == (const this_type*)&r)
202  return *this;
203  return *this = this_type(r);
204  }
206  T& operator*() const {
207  return *this->ref();
208  }
210  T* operator->() const {
211  return this->ref();
212  }
214  bool operator == (const this_type& r) const {
215  return this->ref() == r.ref();
216  }
218  bool operator < (const this_type& r) const {
219  return this->ref() < r.ref();
220  }
222  bool operator != (const this_type& r) const {
223  return this->ref() != r.ref();
224  }
226  bool unique() const {
227  return this->get_count() <= 1;
228  }
230  bool empty() const {
231  return this->get_count() == 0;
232  }
234  operator bool () const {
235  return !empty();
236  }
238  void clear() {
239  this->release();
240  }
241 };
242 
243  }
244 }
245 
246 #include <cgv/config/lib_end.h>
cgv::data::ref_ptr::operator<
bool operator<(const this_type &r) const
compare by pointer
Definition: ref_ptr.h:218
cgv::data::ref_ptr::base_type
ref_ptr_impl< T, is_ref_counted > base_type
type of base class that implements the reference count specific methods
Definition: ref_ptr.h:165
cgv::data::ref_ptr::operator=
this_type & operator=(const this_type &r)
assignment to pointer of same type
Definition: ref_ptr.h:191
cgv::data::ref_ptr_impl::counter_type
struct to store the pointer with a count
Definition: ref_ptr.h:51
cgv::data::ref_ptr::operator*
T & operator*() const
access to element
Definition: ref_ptr.h:206
cgv::data::ref_ptr::clear
void clear()
set to null pointer
Definition: ref_ptr.h:238
cgv::data::ref_ptr::operator->
T * operator->() const
access to element pointer
Definition: ref_ptr.h:210
cgv::data::ref_ptr::operator==
bool operator==(const this_type &r) const
compare by pointer
Definition: ref_ptr.h:214
cgv::data::ref_ptr::up_cast
ref_ptr< S, is_ref_counted > up_cast() const
use static cast to convert from T to S if T is a base class of S and has a virtual destructor
Definition: ref_ptr.h:180
cgv::data::ref_ptr
Definition: ref_ptr.h:19
cgv::data::ref_ptr::ref_ptr
ref_ptr(T *p=0)
construction from pointer or empty if pointer is not given
Definition: ref_ptr.h:168
cgv::data::ref_ptr::ref_ptr
ref_ptr(const ref_ptr< S, is_ref_counted > &s)
allow to copy ref_ptr to a ref_ptr<T> if T is a base class of S and if T has a virtual destructor
Definition: ref_ptr.h:177
cgv::data::ref_ptr::empty
bool empty() const
check if pointer is not yet set
Definition: ref_ptr.h:230
cgv::data::ref_ptr::ref_ptr
ref_ptr(const this_type &r)
copy constructor for reference pointers of the same type
Definition: ref_ptr.h:170
cgv::data::ref_ptr_tag
struct used to make ref pointers to ref_counted friends of ref_counted
Definition: ref_ptr.h:23
cgv::data::ref_ptr_tag::inc_ref_count
void inc_ref_count(const ref_counted *ptr) const
increment the count of a ref counted object
Definition: ref_ptr.h:26
cgv::data::ref_counted
Definition: ref_counted.h:11
cgv::type::cond::has_virtual_destructor
template condition returning, whether the passed type has a virtual destructor
Definition: has_virtual_destructor.h:14
cgv::data::ref_ptr::~ref_ptr
~ref_ptr()
destruct reference counted pointer
Definition: ref_ptr.h:172
cgv::data::ref_counted::get_ref_count
int get_ref_count() const
read access to current count
Definition: ref_counted.h:23
cgv::data::ref_ptr::this_type
ref_ptr< T, is_ref_counted > this_type
type of the reference counted pointer
Definition: ref_ptr.h:163
cgv::data::ref_counted::set_ref_count
void set_ref_count(int c) const
write access is also const to allow ref counted pointers to const instances
Definition: ref_counted.h:20
cgv
the cgv namespace
Definition: vr_calib.cxx:9
cgv::data::ref_ptr::operator!=
bool operator!=(const this_type &r) const
compare by pointer
Definition: ref_ptr.h:222
cgv::data::ref_ptr_tag::dec_ref_count
bool dec_ref_count(const ref_counted *ptr) const
decrement the count of a ref counted object and return whether to delete the object
Definition: ref_ptr.h:31
cgv::data::ref_ptr::unique
bool unique() const
check if this is the only reference
Definition: ref_ptr.h:226
cgv::type::cond::is_base_of
template condition returning, whether the first argument is a base class of the second argument
Definition: is_base_of.h:15