source: orange/source/orange/garbage.hpp @ 6531:57bdc92cd8e9

Revision 6531:57bdc92cd8e9, 8.5 KB checked in by janezd <janez.demsar@…>, 4 years ago (diff)
  • changed licenses to GPL 3.0
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
59#define WRAPPER ORANGE_WRAPPER
60#define VWRAPPER ORANGE_VWRAPPER
61
62#ifdef _MSC_VER
63  #include <crtdbg.h>
64  #pragma warning (disable : 4231 4660 4661 4786 4114 4018 4267 4244 4702 4710 4290 4251 4275)
65  #pragma warning (disable : 4786 4114 4018 4267 4127)
66  #define TYPENAME(x) (x).name()+7
67
68#else
69  #include <assert.h>
70  #define _ASSERT assert
71  char *demangle(const type_info &type);
72  #define TYPENAME(x) demangle(x)+1
73#endif
74
75#define mlnew new
76#define mldelete delete
77
78class TOrangeType;
79extern ORANGE_API PyTypeObject PyOrNonOrange_Type;
80extern ORANGE_API TOrangeType PyOrOrange_Type;
81
82class TWrapped;
83
84class TGCCounter {
85public:
86    PyObject_HEAD
87  TWrapped *ptr;
88  PyObject *orange_dict;
89  bool call_constructed, is_reference;
90
91  inline void getRef()
92  { Py_INCREF(this); }
93
94  inline void freeRef()
95  { Py_DECREF(this); }
96};
97
98
99class ORANGE_API TWrapped {
100public:
101  TGCCounter *myWrapper;
102
103  TWrapped()
104  : myWrapper(NULL)
105  {}
106
107  virtual ~TWrapped()
108  {}
109};
110
111
112/* Checks whether the object is gc-tracked or not.
113   This way, we distinguish between wrapped pointers (which are)
114   and wrapped references (which are not wrapped).
115   The latter don't get freed. */
116
117#define PyObject_IsPointer(o) (((PyGC_Head *)(o)-1)->gc.gc_next != NULL)
118#define PyObject_IsReference(o) (((PyGC_Head *)(o)-1)->gc.gc_next == NULL)
119 
120typedef TGCCounter TPyOrange;
121
122#define VISIT(obj) { int res=visit((PyObject *)(obj), arg); if (res) return res; }
123
124class ORANGE_API TWrapper {
125public:
126  TGCCounter *counter;
127
128  inline void init() // used when GCPtr is allocated in C code and constructor is not called
129  { counter = NULL; }
130
131  inline TWrapper()
132  : counter(NULL)
133  {}
134
135
136  inline TWrapper(TGCCounter *ac)
137  : counter(ac)
138  {
139    if (counter)
140      counter->getRef();
141  }
142
143
144  inline operator bool() const
145  { return (counter!=NULL); }
146
147
148  ~TWrapper()
149  { if (counter)
150      counter->freeRef();
151  }
152};
153
154
155template<class T>
156class GCPtr : public TWrapper {
157public:
158
159  inline GCPtr() 
160  {};
161
162
163  inline GCPtr(TGCCounter *acounter, bool)  // Used by PyOrange_AS_Orange
164  : TWrapper(acounter)
165  {}
166
167
168  inline GCPtr(T *ptr)
169  { 
170    if (ptr)
171      if (((TWrapped *)ptr)->myWrapper) {
172        counter = ((TWrapped *)ptr)->myWrapper;
173        counter->getRef();
174      }
175      else {
176        counter = PyObject_GC_New(TGCCounter, (PyTypeObject *)&PyOrOrange_Type);
177        counter->orange_dict = NULL;
178        counter->call_constructed = false;
179        counter->is_reference = false;
180        counter->ptr = (TWrapped *)ptr;
181        ((TWrapped *)ptr)->myWrapper = counter;
182        PyObject_GC_Track(counter);
183      }
184  }
185
186
187  inline GCPtr(T *ptr, PyTypeObject *type)
188  { 
189    if (ptr) {
190      counter = (TGCCounter *)type->tp_alloc(type, 0);
191      counter->orange_dict = NULL;
192      counter->call_constructed = false;
193      counter->is_reference = false;
194      counter->ptr = (TWrapped *)ptr;
195      _ASSERT(!((TWrapped *)ptr)->myWrapper);
196      ((TWrapped *)ptr)->myWrapper = counter;
197    }
198  }
199
200
201  inline explicit GCPtr(T &ptr) 
202  { 
203    counter = PyObject_GC_New(TGCCounter, (PyTypeObject *)&PyOrOrange_Type);
204    counter->orange_dict = NULL;
205    counter->call_constructed = false;
206    counter->is_reference = true; // this should never be deleted
207    counter->ptr = (TWrapped *)&ptr;
208    /* No calling PyObject_GC_Track(counter);
209       These objects cannot be freed; if they participate in a cycle, the cycle
210       will disappear as soon as they die (and these objects die soon).
211       We even distinguish between wrapped pointers and reference by checking
212       whether they are gc-tracked or not. */
213  }
214
215
216  template<class U>
217  GCPtr(const GCPtr<U> &other)
218  : TWrapper(other.counter)
219  { if (counter) {
220      if (!dynamic_cast<T *>(other.counter->ptr))
221        raiseError("bad cast from %s to %s", typeid(U).name(), typeid(T).name());
222    }
223  }
224
225
226/*  GCPtr(const TWrapper &other)
227  : TWrapper(other.counter)
228  {
229    if (counter && !dynamic_cast<T *>(other.counter->ptr))
230      raiseError("bad cast from %s to %s", typeid(other).name(), typeid(T).name());
231  }
232*/
233
234  GCPtr(const GCPtr<T> &other)
235  : TWrapper(other.counter)
236  {}
237
238
239  GCPtr<T> & operator =(const GCPtr<T> &other)
240  { 
241    if (other.counter)
242      other.counter->getRef();
243    if (counter)
244      counter->freeRef();
245    counter = other.counter;
246    return *this;
247  }
248
249
250  inline T *operator -> ()
251  { 
252    if (!counter)
253      raiseError("Orange internal error: NULL pointer to '%s'", TYPENAME(typeid(T)));
254    return (T *)counter->ptr;
255  }
256
257
258  inline const T *operator -> () const 
259  { 
260    if (!counter)
261      raiseError("Orange internal error: NULL pointer to '%s'", TYPENAME(typeid(T)));
262    return (T *)counter->ptr;
263  }
264
265
266  inline bool operator ==(const TWrapper &p2) const
267  { return  (   !counter && !p2.counter)
268             || (counter && p2.counter && (counter->ptr==p2.counter->ptr));
269  }
270 
271
272  inline bool operator ==(const TWrapped *p2) const
273  { return    (!counter && !p2) 
274           || ( counter && (counter->ptr==p2));
275  }
276
277
278  inline bool operator !=(const TWrapper &p2) const
279  { return    (!counter &&  p2.counter)
280           || ( counter && !p2.counter)
281           || ( counter &&  p2.counter && (counter->ptr!=p2.counter->ptr));
282  }
283
284
285  inline bool operator !=(const TWrapped *p2) const
286  { return    (!counter && p2)
287           || ( counter && (counter->ptr!=p2));
288  }
289
290  inline bool operator < (const GCPtr<T> &ps) const
291  { return    (!counter && ps.counter)
292           || (int(counter->ptr) < int(ps.counter->ptr)); }
293
294
295  inline T *getUnwrappedPtr()
296  { return counter ? (T *)counter->ptr : NULL; }
297
298
299  inline T &getReference()
300  { if (!counter)
301      raiseError("Orange internal error: NULL pointer to '%s'", TYPENAME(typeid(T)));
302    return (T &)*counter->ptr;
303  }
304
305
306  inline T const *getUnwrappedPtr() const
307  { return counter ? (T const *)counter->ptr : NULL; }
308
309
310  inline T &getReference() const
311  { if (!counter)
312      raiseError("Orange internal error: NULL pointer to '%s'", TYPENAME(typeid(T)));
313    return (T &)*counter->ptr;
314  }
315
316
317  template<class U>
318  inline bool castable_to(const U *) const
319  { return (dynamic_cast<U *>(counter->ptr)!=NULL); }
320
321
322  template<class U>
323  inline U *as(U *)
324  { return counter ? dynamic_cast<U *>(counter->ptr) : NULL; }
325
326
327  template<class U>
328  inline const U *as(U *) const
329  { return counter ? dynamic_cast<const U *>(counter->ptr) : NULL;  }
330};
331
332
333template<class T, class U>
334inline bool castable_to(GCPtr<T> obj, U *)
335{ return (dynamic_cast<U *>(obj.counter->ptr) != NULL); }
336
337
338#define is_derived_from(x) castable_to((x *)NULL)
339#define AS(x) as((x *)NULL)
340
341#define CAST(o,x) ((o).counter ? dynamic_cast<x *>((o).counter->ptr) : NULL)
342
343#define WRAPPEDVECTOR(x) GCPtrNML<vector<x> >
344
345
346#endif
Note: See TracBrowser for help on using the repository browser.