libt3widget
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups
ptr.h
1 /* Copyright (C) 2011-2012 G.P. Halkes
2  This program is free software: you can redistribute it and/or modify
3  it under the terms of the GNU General Public License version 3, as
4  published by the Free Software Foundation.
5 
6  This program is distributed in the hope that it will be useful,
7  but WITHOUT ANY WARRANTY; without even the implied warranty of
8  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  GNU General Public License for more details.
10 
11  You should have received a copy of the GNU General Public License
12  along with this program. If not, see <http://www.gnu.org/licenses/>.
13 */
14 #ifndef T3_WIDGET_PTR_H
15 #define T3_WIDGET_PTR_H
16 
17 #include <cstdlib>
18 
19 namespace t3_widget {
20 
21 template <typename T>
23  void operator()(T* p) { delete p; }
24 };
25 
26 template <typename T>
27 struct delete_functor<T []> {
28  void operator()(T* p) { delete [] p; }
29 };
30 
31 template <typename T = void, void (*f)(T *) = free>
32 struct free_func {
33  void operator()(T *p) { f((T *) p); }
34 };
35 
36 template <typename T, typename U, U (*f)(T *)>
37 struct free_func2 {
38  void operator()(T *p) { f((T *) p); }
39 };
40 
41 template <typename T>
42 class T3_WIDGET_API smartptr_base {
43  public:
44  T* operator-> (void) const { return p_; }
45  T& operator* (void) const { return *p_; }
46  T* operator() (void) const { return p_; }
47  operator T* (void) { return p_; }
48  T* get(void) { return p_; }
49  protected:
50  smartptr_base(void) : p_(NULL) {}
51  T* p_;
52 };
53 
54 /* To allow typedef of the templates, we use the typedef in template class
55  trick. For readability we include a macro for this purpose here. This will
56  define a type t in the class name such that name<T>::t will be the type. This
57  is sort of in line with the _t suffix we use for types.
58 
59  Because the template arguments that we want to pass as the last parameter will
60  be considered separate macro parameters, we use a simple trick: we use a
61  variadic macro, and use __VA_ARGS__ where we want the template. */
62 #define _T3_WIDGET_TYPEDEF(name, ...) \
63 class T3_WIDGET_API name { \
64  public: \
65  typedef __VA_ARGS__ t; \
66  private: \
67  name(void) {} \
68 }
69 
70 /* Pointer wrapper which automatically de-allocate its objects when going out
71  of scope. The difference with the Boost scoped_ptr is that the objects can
72  be released. Their main use is to ensure deallocation during exception
73  handling, and storing of temporary values.
74 
75  Furthermore, these pointer wrappers are more generic than the std::auto_ptr,
76  in that a functor can be passed to perform the clean-up, instead of
77  requiring delete.
78 */
79 #define _T3_WIDGET_DEFINE_CLEANUP_PTR \
80  public: \
81  ~cleanup_ptr_base(void) { if (smartptr_base<T>::p_ != NULL) { D d; d(smartptr_base<T>::p_); } } \
82  cleanup_ptr_base(void) {} \
83  cleanup_ptr_base(T *p) { smartptr_base<T>::p_ = p; } \
84  T** operator& (void) { return &smartptr_base<T>::p_; } \
85  T* operator= (T *p) { \
86  if (smartptr_base<T>::p_ == p) \
87  return p; \
88  if (smartptr_base<T>::p_ != NULL) { \
89  D d; \
90  d(smartptr_base<T>::p_); \
91  } \
92  return smartptr_base<T>::p_ = p; \
93  } \
94  T *release(void) { T *p = smartptr_base<T>::p_; smartptr_base<T>::p_ = NULL; return p; } \
95  private: \
96  cleanup_ptr_base& operator= (const cleanup_ptr_base &p) { (void) p; return *this; } \
97  cleanup_ptr_base(const cleanup_ptr_base &p) { (void) p; }
98 
99 template <typename T, typename D>
100 class T3_WIDGET_API cleanup_ptr_base : public smartptr_base<T> {
101  _T3_WIDGET_DEFINE_CLEANUP_PTR
102 };
103 
104 template <typename T, typename D>
105 class T3_WIDGET_API cleanup_ptr_base<T[], D> : public smartptr_base<T> {
106  _T3_WIDGET_DEFINE_CLEANUP_PTR
107 };
108 #undef _T3_WIDGET_DEFINE_CLEANUP_PTR
109 
110 /* We also typedef what would be the basic variant, such that all type names
111  use the same pattern. */
112 template <typename T, typename D = delete_functor<T> > _T3_WIDGET_TYPEDEF(cleanup_ptr, cleanup_ptr_base<T, D>);
113 template <typename T, void (*f)(T *)> _T3_WIDGET_TYPEDEF(cleanup_func_ptr, cleanup_ptr_base<T, free_func<T, f> >);
114 template <typename T, typename U, U (*f)(T *)> _T3_WIDGET_TYPEDEF(cleanup_func2_ptr, cleanup_ptr_base<T, free_func2<T, U, f> >);
115 template <typename T> _T3_WIDGET_TYPEDEF(cleanup_free_ptr, cleanup_ptr_base<T, free_func<> >);
116 
117 /* Pointer wrapper using reference linking. These can be allocated on the stack
118  in their entirety, in contrast to reference counted pointers which always
119  have a heap allocated part. These will never throw a bad_alloc exception.
120 
121  Note that in link_p we use several dirty tricks: we need a pointer to other.
122  However, taking the address of a reference doesn't work. So we use
123  other.next->prev, which points to other. Furthermore, we go through our own
124  pointer to other to modify it, because simply trying to modify other is not
125  allowed because it is const. Not having it const causes problems elsewhere.
126 */
127 #define _T3_WIDGET_DEFINE_LINKED_PTR \
128  public: \
129  linked_ptr_base(void) : next(this), prev(this) {} \
130  linked_ptr_base(T *p) { set_p(p); } \
131  linked_ptr_base(const linked_ptr_base &other) { link_p(other); } \
132  ~linked_ptr_base(void) { set_p(NULL); } \
133  linked_ptr_base& operator= (const linked_ptr_base &other) { link_p(other); return *this; } \
134  T* operator= (T *p) { set_p(p); return smartptr_base<T>::p_; } \
135  private: \
136  void set_p(T *p) { \
137  if (smartptr_base<T>::p_ == p) \
138  return; \
139  if (smartptr_base<T>::p_ != NULL) { \
140  if (next == this && prev == this) { \
141  D d; \
142  d(smartptr_base<T>::p_); \
143  } else { \
144  next->prev = prev; \
145  prev->next = next; \
146  } \
147  } \
148  smartptr_base<T>::p_ = p; \
149  next = this; \
150  prev = this; \
151  } \
152  void link_p(const linked_ptr_base &other) { \
153  set_p(other.p_); \
154  next = other.next->prev; \
155  prev = other.prev; \
156  prev->next = this; \
157  next->prev = this; \
158  } \
159  linked_ptr_base *next, *prev; \
160 
161 template <typename T, typename D>
162 class T3_WIDGET_API linked_ptr_base : public smartptr_base<T> {
163  _T3_WIDGET_DEFINE_LINKED_PTR
164 };
165 
166 template <typename T, typename D>
167 class T3_WIDGET_API linked_ptr_base<T[], D> : public smartptr_base<T> {
168  _T3_WIDGET_DEFINE_LINKED_PTR
169 };
170 
171 /* We also typedef what would be the basic variant, such that all type names
172  use the same pattern. */
173 template <typename T, typename D = delete_functor<T> > _T3_WIDGET_TYPEDEF(linked_ptr, linked_ptr_base<T, D>);
174 
175 /* The following pointers are meant only for private implemenation purposes,
176  therfore no assignment is possible, and only the constructor with argument
177  is available. Other than that, they are normal auto-pointers.
178 */
179 template <typename T>
180 class T3_WIDGET_API pimpl_ptr_base : public smartptr_base<T> {
181  public:
182  ~pimpl_ptr_base(void) { if (smartptr_base<T>::p_ != NULL) delete smartptr_base<T>::p_; }
183  pimpl_ptr_base(T *p) { smartptr_base<T>::p_ = p; }
184  private:
185  pimpl_ptr_base& operator= (const pimpl_ptr_base &p) { (void) p; return *this; }
186  pimpl_ptr_base(const pimpl_ptr_base &p) { (void) p; }
187 };
188 /* We also typedef what would be the basic variant, such that all type names
189  use the same pattern. */
190 template <typename T> _T3_WIDGET_TYPEDEF(pimpl_ptr, pimpl_ptr_base<T>);
191 
192 #undef _T3_WIDGET_TYPEDEF
193 }; // namespace
194 #endif
Definition: ptr.h:37
Definition: ptr.h:180
Definition: ptr.h:22
Definition: ptr.h:162
Definition: ptr.h:100
Definition: ptr.h:32
Definition: ptr.h:42