source: orange/source/orange/garbage.hpp @ 10887:43fcaa1ba432

Revision 10887:43fcaa1ba432, 8.5 KB checked in by Bobby Powers <bobby@…>, 2 years ago (diff)

headers: clean up #includes

This both reduces noise and fixes a build error from my distro's gcc
4.7.

Line 
1/*
2    This file is part of Orange.
3   
4    Copyright 1996-2010 Faculty of Computer and Information Science, University of Ljubljana
5    Contact: janez.demsar@fri.uni-lj.si
6
7    Orange is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Orange is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Orange.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21
22#ifndef __GARBAGE_HPP
23#define __GARBAGE_HPP
24
25/*
26
27On wrapping pointers vs. wrapping references
28
29Wrapping references can speed up save execution time since stack allocation is
30somewhat faster than heap allocations
31
32
33Wrapping references is allowed, but risky. The corresponding constructor
34is declared as 'explicit' to make sure that it is not called in error.
35
36Sending wrapped reference is OK if the called function won't store it.
37Example of such function is operator() of TMeasure methods that uses
38PDistribution only to assess the quality of the attribute. But even in
39such cases one must be cautious: what if a more complex measure, such
40as ReliefF, stores something to speed up the next computation?
41Because of such assumptions, it is recommended that someone that
42'unexpectedly' stores something checks that the stored item is not a
43wrapped reference using PyObject_IsReference macro.
44
45In addition, you may wrap a reference if you know for sure that the
46object receiving the wrapper will die before the wrapped object.
47
48.
49*/
50
51#include <typeinfo>
52#include <stdio.h>
53#include <Python.h>
54using namespace std;
55
56// Not the most appropriate, but surely the most suitable place:
57#include "px/orange_globals.hpp"
58#include "errors.hpp"
59
60#define WRAPPER ORANGE_WRAPPER
61#define VWRAPPER ORANGE_VWRAPPER
62
63#ifdef _MSC_VER
64  #include <crtdbg.h>
65  #pragma warning (disable : 4231 4660 4661 4786 4114 4018 4267 4244 4702 4710 4290 4251 4275)
66  #pragma warning (disable : 4786 4114 4018 4267 4127)
67  #define TYPENAME(x) (x).name()+7
68
69#else
70  #include <assert.h>
71  #define _ASSERT assert
72  char *demangle(const type_info &type);
73  #define TYPENAME(x) demangle(x)+1
74#endif
75
76#define mlnew new
77#define mldelete delete
78
79class TOrangeType;
80extern ORANGE_API PyTypeObject PyOrNonOrange_Type;
81extern ORANGE_API TOrangeType PyOrOrange_Type;
82
83class TWrapped;
84
85class TGCCounter {
86public:
87    PyObject_HEAD
88  TWrapped *ptr;
89  PyObject *orange_dict;
90  bool call_constructed, is_reference;
91
92  inline void getRef()
93  { Py_INCREF(this); }
94
95  inline void freeRef()
96  { Py_DECREF(this); }
97};
98
99
100class ORANGE_API TWrapped {
101public:
102  TGCCounter *myWrapper;
103
104  TWrapped()
105  : myWrapper(NULL)
106  {}
107
108  virtual ~TWrapped()
109  {}
110};
111
112
113/* Checks whether the object is gc-tracked or not.
114   This way, we distinguish between wrapped pointers (which are)
115   and wrapped references (which are not wrapped).
116   The latter don't get freed. */
117
118#define PyObject_IsPointer(o) (((PyGC_Head *)(o)-1)->gc.gc_next != NULL)
119#define PyObject_IsReference(o) (((PyGC_Head *)(o)-1)->gc.gc_next == NULL)
120 
121typedef TGCCounter TPyOrange;
122
123#define VISIT(obj) { int res=visit((PyObject *)(obj), arg); if (res) return res; }
124
125class ORANGE_API TWrapper {
126public:
127  TGCCounter *counter;
128
129  inline void init() // used when GCPtr is allocated in C code and constructor is not called
130  { counter = NULL; }
131
132  inline TWrapper()
133  : counter(NULL)
134  {}
135
136
137  inline TWrapper(TGCCounter *ac)
138  : counter(ac)
139  {
140    if (counter)
141      counter->getRef();
142  }
143
144
145  inline operator bool() const
146  { return (counter!=NULL); }
147
148
149  ~TWrapper()
150  { if (counter)
151      counter->freeRef();
152  }
153};
154
155
156template<class T>
157class GCPtr : public TWrapper {
158public:
159
160  inline GCPtr() 
161  {};
162
163
164  inline GCPtr(TGCCounter *acounter, bool)  // Used by PyOrange_AS_Orange
165  : TWrapper(acounter)
166  {}
167
168
169  inline GCPtr(T *ptr)
170  { 
171    if (ptr)
172      if (((TWrapped *)ptr)->myWrapper) {
173        counter = ((TWrapped *)ptr)->myWrapper;
174        counter->getRef();
175      }
176      else {
177        counter = PyObject_GC_New(TGCCounter, (PyTypeObject *)&PyOrOrange_Type);
178        counter->orange_dict = NULL;
179        counter->call_constructed = false;
180        counter->is_reference = false;
181        counter->ptr = (TWrapped *)ptr;
182        ((TWrapped *)ptr)->myWrapper = counter;
183        PyObject_GC_Track(counter);
184      }
185  }
186
187
188  inline GCPtr(T *ptr, PyTypeObject *type)
189  { 
190    if (ptr) {
191      counter = (TGCCounter *)type->tp_alloc(type, 0);
192      counter->orange_dict = NULL;
193      counter->call_constructed = false;
194      counter->is_reference = false;
195      counter->ptr = (TWrapped *)ptr;
196      _ASSERT(!((TWrapped *)ptr)->myWrapper);
197      ((TWrapped *)ptr)->myWrapper = counter;
198    }
199  }
200
201
202  inline explicit GCPtr(T &ptr) 
203  { 
204    counter = PyObject_GC_New(TGCCounter, (PyTypeObject *)&PyOrOrange_Type);
205    counter->orange_dict = NULL;
206    counter->call_constructed = false;
207    counter->is_reference = true; // this should never be deleted
208    counter->ptr = (TWrapped *)&ptr;
209    /* No calling PyObject_GC_Track(counter);
210       These objects cannot be freed; if they participate in a cycle, the cycle
211       will disappear as soon as they die (and these objects die soon).
212       We even distinguish between wrapped pointers and reference by checking
213       whether they are gc-tracked or not. */
214  }
215
216
217  template<class U>
218  GCPtr(const GCPtr<U> &other)
219  : TWrapper(other.counter)
220  { if (counter) {
221      if (!dynamic_cast<T *>(other.counter->ptr))
222        raiseError("bad cast from %s to %s", typeid(U).name(), typeid(T).name());
223    }
224  }
225
226
227/*  GCPtr(const TWrapper &other)
228  : TWrapper(other.counter)
229  {
230    if (counter && !dynamic_cast<T *>(other.counter->ptr))
231      raiseError("bad cast from %s to %s", typeid(other).name(), typeid(T).name());
232  }
233*/
234
235  GCPtr(const GCPtr<T> &other)
236  : TWrapper(other.counter)
237  {}
238
239
240  GCPtr<T> & operator =(const GCPtr<T> &other)
241  { 
242    if (other.counter)
243      other.counter->getRef();
244    if (counter)
245      counter->freeRef();
246    counter = other.counter;
247    return *this;
248  }
249
250
251  inline T *operator -> ()
252  { 
253    if (!counter)
254      raiseError("Orange internal error: NULL pointer to '%s'", TYPENAME(typeid(T)));
255    return (T *)counter->ptr;
256  }
257
258
259  inline const T *operator -> () const 
260  { 
261    if (!counter)
262      raiseError("Orange internal error: NULL pointer to '%s'", TYPENAME(typeid(T)));
263    return (T *)counter->ptr;
264  }
265
266
267  inline bool operator ==(const TWrapper &p2) const
268  { return  (   !counter && !p2.counter)
269             || (counter && p2.counter && (counter->ptr==p2.counter->ptr));
270  }
271 
272
273  inline bool operator ==(const TWrapped *p2) const
274  { return    (!counter && !p2) 
275           || ( counter && (counter->ptr==p2));
276  }
277
278
279  inline bool operator !=(const TWrapper &p2) const
280  { return    (!counter &&  p2.counter)
281           || ( counter && !p2.counter)
282           || ( counter &&  p2.counter && (counter->ptr!=p2.counter->ptr));
283  }
284
285
286  inline bool operator !=(const TWrapped *p2) const
287  { return    (!counter && p2)
288           || ( counter && (counter->ptr!=p2));
289  }
290
291  inline bool operator < (const GCPtr<T> &ps) const
292  { return    (!counter && ps.counter)
293           || (int(counter->ptr) < int(ps.counter->ptr)); }
294
295
296  inline T *getUnwrappedPtr()
297  { return counter ? (T *)counter->ptr : NULL; }
298
299
300  inline T &getReference()
301  { if (!counter)
302      raiseError("Orange internal error: NULL pointer to '%s'", TYPENAME(typeid(T)));
303    return (T &)*counter->ptr;
304  }
305
306
307  inline T const *getUnwrappedPtr() const
308  { return counter ? (T const *)counter->ptr : NULL; }
309
310
311  inline T &getReference() const
312  { if (!counter)
313      raiseError("Orange internal error: NULL pointer to '%s'", TYPENAME(typeid(T)));
314    return (T &)*counter->ptr;
315  }
316
317
318  template<class U>
319  inline bool castable_to(const U *) const
320  { return (dynamic_cast<U *>(counter->ptr)!=NULL); }
321
322
323  template<class U>
324  inline U *as(U *)
325  { return counter ? dynamic_cast<U *>(counter->ptr) : NULL; }
326
327
328  template<class U>
329  inline const U *as(U *) const
330  { return counter ? dynamic_cast<const U *>(counter->ptr) : NULL;  }
331};
332
333
334template<class T, class U>
335inline bool castable_to(GCPtr<T> obj, U *)
336{ return (dynamic_cast<U *>(obj.counter->ptr) != NULL); }
337
338
339#define is_derived_from(x) castable_to((x *)NULL)
340#define AS(x) as((x *)NULL)
341
342#define CAST(o,x) ((o).counter ? dynamic_cast<x *>((o).counter->ptr) : NULL)
343
344#define WRAPPEDVECTOR(x) GCPtrNML<vector<x> >
345
346
347#endif
Note: See TracBrowser for help on using the repository browser.