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