BGE performance, 4th round: logic
[blender.git] / source / gameengine / Ketsji / KX_PythonSeq.cpp
1 /**
2  * $Id: 
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Campbell Barton
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  * Readonly sequence wrapper for lookups on logic bricks
29  */
30
31
32 #include "KX_PythonSeq.h"
33 #include "KX_GameObject.h"
34 #include "SCA_ISensor.h"
35 #include "SCA_IController.h"
36 #include "SCA_IActuator.h"
37
38
39 PyObject *KX_PythonSeq_CreatePyObject( PyObject *base, short type )
40 {
41         KX_PythonSeq *seq = PyObject_NEW( KX_PythonSeq, &KX_PythonSeq_Type);
42         seq->base = base;
43         Py_INCREF(base); /* so we can always access to check if its valid */
44         seq->type = type;
45         seq->iter = -1; /* init */
46         return (PyObject *)seq;
47  }
48  
49  static void KX_PythonSeq_dealloc( KX_PythonSeq * self )
50 {
51         Py_DECREF(self->base);
52         PyObject_DEL( self );
53 }
54
55 static Py_ssize_t KX_PythonSeq_len( KX_PythonSeq * self )
56 {
57         PyObjectPlus *self_plus= BGE_PROXY_REF(self->base);
58          
59         if(self_plus==NULL) {
60                 PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
61                 return -1;
62         }
63         
64         switch(self->type) {
65         case KX_PYGENSEQ_CONT_TYPE_SENSORS:
66                 return ((SCA_IController *)self_plus)->GetLinkedSensors().size();
67         case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
68                 return ((SCA_IController *)self_plus)->GetLinkedActuators().size();
69         case KX_PYGENSEQ_OB_TYPE_SENSORS:
70                 return ((KX_GameObject *)self_plus)->GetSensors().size();
71         case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
72                 return ((KX_GameObject *)self_plus)->GetControllers().size();
73         case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
74                 return ((KX_GameObject *)self_plus)->GetActuators().size();
75         default:
76                 /* Should never happen */
77                 PyErr_SetString(PyExc_SystemError, "invalid type, internal error");
78                 return -1;
79         }
80 }
81
82 static PyObject *KX_PythonSeq_getIndex(KX_PythonSeq * self, int index)
83 {
84         PyObjectPlus *self_plus= BGE_PROXY_REF(self->base);
85          
86         if(self_plus==NULL) {
87                 PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
88                 return NULL;
89         }
90         
91         switch(self->type) {
92                 case KX_PYGENSEQ_CONT_TYPE_SENSORS:
93                 {
94                         vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
95                         if(index<0) index += linkedsensors.size();
96                         if(index<0 || index>= linkedsensors.size()) {
97                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
98                                 return NULL;
99                         }
100                         return linkedsensors[index]->GetProxy();
101                 }
102                 case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
103                 {
104                         vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
105                         if(index<0) index += linkedactuators.size();
106                         if(index<0 || index>= linkedactuators.size()) {
107                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
108                                 return NULL;
109                         }
110                         return linkedactuators[index]->GetProxy();
111                 }
112                 case KX_PYGENSEQ_OB_TYPE_SENSORS:
113                 {
114                         SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
115                         if(index<0) index += linkedsensors.size();
116                         if(index<0 || index>= linkedsensors.size()) {
117                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
118                                 return NULL;
119                         }
120                         return linkedsensors[index]->GetProxy();
121                 }
122                 case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
123                 {
124                         SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
125                         if(index<0) index += linkedcontrollers.size();
126                         if(index<0 || index>= linkedcontrollers.size()) {
127                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
128                                 return NULL;
129                         }
130                         return linkedcontrollers[index]->GetProxy();
131                 }
132                 case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
133                 {
134                         SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
135                         if(index<0) index += linkedactuators.size();
136                         if(index<0 || index>= linkedactuators.size()) {
137                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
138                                 return NULL;
139                         }
140                         return linkedactuators[index]->GetProxy();
141                 }
142         }
143         
144         PyErr_SetString(PyExc_SystemError, "invalid sequence type, this is a bug");
145         return NULL;
146 }
147
148
149 static PyObject * KX_PythonSeq_subscript(KX_PythonSeq * self, PyObject *key)
150 {
151         PyObjectPlus *self_plus= BGE_PROXY_REF(self->base);
152         char *name = NULL;
153         
154         if(self_plus==NULL) {
155                 PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
156                 return NULL;
157         }
158         
159         if (PyInt_Check(key)) {
160                 return KX_PythonSeq_getIndex(self, PyInt_AS_LONG( key ));
161         } else if ( PyString_Check(key) ) {
162                 name = PyString_AsString( key );
163         } else {
164                 PyErr_SetString( PyExc_TypeError, "expected a string or an index" );
165                 return NULL;
166         }
167         
168         switch(self->type) {
169                 case KX_PYGENSEQ_CONT_TYPE_SENSORS:
170                 {
171                         vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
172                         SCA_ISensor* sensor;
173                         for (unsigned int index=0;index<linkedsensors.size();index++) {
174                                 sensor = linkedsensors[index];
175                                 if (sensor->GetName() == name)
176                                         return sensor->GetProxy();
177                         }
178                         break;
179                 }
180                 case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
181                 {
182                         vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
183                         SCA_IActuator* actuator;
184                         for (unsigned int index=0;index<linkedactuators.size();index++) {
185                                 actuator = linkedactuators[index];
186                                 if (actuator->GetName() == name)
187                                         return actuator->GetProxy();
188                         }
189                         break;
190                 }
191                 case KX_PYGENSEQ_OB_TYPE_SENSORS:
192                 {
193                         SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
194                         SCA_ISensor *sensor;
195                         for (unsigned int index=0;index<linkedsensors.size();index++) {
196                                 sensor= linkedsensors[index];
197                                 if (sensor->GetName() == name)
198                                         return sensor->GetProxy();
199                         }
200                         break;
201                 }
202                 case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
203                 {
204                         SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
205                         SCA_IController *controller;
206                         for (unsigned int index=0;index<linkedcontrollers.size();index++) {
207                                 controller= linkedcontrollers[index];
208                                 if (controller->GetName() == name)
209                                         return controller->GetProxy();
210                         }
211                         break;
212                 }
213                 case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
214                 {
215                         SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
216                         SCA_IActuator *actuator;
217                         for (unsigned int index=0;index<linkedactuators.size();index++) {
218                                 actuator= linkedactuators[index];
219                                 if (actuator->GetName() == name)
220                                         return actuator->GetProxy();
221                         }
222                         break;
223                 }
224         }
225         
226         PyErr_Format( PyExc_KeyError, "requested item \"%s\" does not exist", name);
227         return NULL;
228 }
229
230 static PyMappingMethods KX_PythonSeq_as_mapping = {
231         ( inquiry ) KX_PythonSeq_len,   /* mp_length */
232         ( binaryfunc ) KX_PythonSeq_subscript,  /* mp_subscript */
233         0,      /* mp_ass_subscript */
234 };
235
236
237 /*
238  * Initialize the interator index
239  */
240
241 static PyObject *KX_PythonSeq_getIter( KX_PythonSeq * self )
242 {
243         if(BGE_PROXY_REF(self->base)==NULL) {
244                 PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
245                 return NULL;
246         }
247         
248         /* create a new iterator if were alredy using this one */
249         if (self->iter == -1) {
250                 self->iter = 0;
251                 Py_INCREF(self);
252                 return (PyObject *)self;
253         } else {
254                 return KX_PythonSeq_CreatePyObject(self->base, self->type);
255         }
256  }
257  
258
259 /*
260  * Return next KX_PythonSeq iter.
261  */
262  
263 static PyObject *KX_PythonSeq_nextIter( KX_PythonSeq * self )
264 {
265         PyObject *object = KX_PythonSeq_getIndex(self, self->iter);
266         
267         self->iter++;
268         if( object==NULL ) {
269                 self->iter= -1; /* for reuse */
270                 PyErr_SetString(PyExc_StopIteration,    "iterator at end");
271         }
272         return object; /* can be NULL for end of iterator */
273 }
274
275
276 static int KX_PythonSeq_compare( KX_PythonSeq * a, KX_PythonSeq * b ) /* TODO - python3.x wants richcmp */
277 {
278         return ( a->type == b->type && a->base == b->base) ? 0 : -1;    
279 }
280
281 /*
282  * repr function
283  * convert to a list and get its string value
284  */
285 static PyObject *KX_PythonSeq_repr( KX_PythonSeq * self )
286 {
287         PyObject *list = PySequence_List((PyObject *)self);
288         PyObject *repr = PyObject_Repr(list);
289         Py_DECREF(list);
290         return repr;
291 }
292
293
294 /*****************************************************************************/
295 /* Python KX_PythonSeq_Type structure definition:                               */
296 /*****************************************************************************/
297 PyTypeObject KX_PythonSeq_Type = {
298 #if (PY_VERSION_HEX >= 0x02060000)
299         PyVarObject_HEAD_INIT(NULL, 0)
300 #else
301         /* python 2.5 and below */
302         PyObject_HEAD_INIT( NULL )  /* required py macro */
303         0,                          /* ob_size */
304 #endif
305         /*  For printing, in format "<module>.<name>" */
306         "KX_PythonSeq",           /* char *tp_name; */
307         sizeof( KX_PythonSeq ),       /* int tp_basicsize; */
308         0,                          /* tp_itemsize;  For allocation */
309
310         /* Methods to implement standard operations */
311
312         ( destructor ) KX_PythonSeq_dealloc, /* destructor tp_dealloc; */
313         NULL,                       /* printfunc tp_print; */
314         NULL,                       /* getattrfunc tp_getattr; */
315         NULL,                       /* setattrfunc tp_setattr; */
316         ( cmpfunc ) KX_PythonSeq_compare, /* cmpfunc tp_compare; */
317         ( reprfunc ) KX_PythonSeq_repr,   /* reprfunc tp_repr; */
318
319         /* Method suites for standard classes */
320
321         NULL,                       /* PyNumberMethods *tp_as_number; */
322         NULL,       /* PySequenceMethods *tp_as_sequence; */
323         &KX_PythonSeq_as_mapping,                       /* PyMappingMethods *tp_as_mapping; */
324
325         /* More standard operations (here for binary compatibility) */
326
327         NULL,                       /* hashfunc tp_hash; */
328         NULL,                       /* ternaryfunc tp_call; */
329         NULL,                       /* reprfunc tp_str; */
330         NULL,                       /* getattrofunc tp_getattro; */
331         NULL,                       /* setattrofunc tp_setattro; */
332
333         /* Functions to access object as input/output buffer */
334         NULL,                       /* PyBufferProcs *tp_as_buffer; */
335
336   /*** Flags to define presence of optional/expanded features ***/
337         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
338
339         NULL,                       /*  char *tp_doc;  Documentation string */
340   /*** Assigned meaning in release 2.0 ***/
341         /* call function for all accessible objects */
342         NULL,                       /* traverseproc tp_traverse; */
343
344         /* delete references to contained objects */
345         NULL,                       /* inquiry tp_clear; */
346
347   /***  Assigned meaning in release 2.1 ***/
348   /*** rich comparisons ***/
349         NULL,                       /* richcmpfunc tp_richcompare; */
350
351   /***  weak reference enabler ***/
352         0,                          /* long tp_weaklistoffset; */
353
354   /*** Added in release 2.2 ***/
355         /*   Iterators */
356         ( getiterfunc) KX_PythonSeq_getIter, /* getiterfunc tp_iter; */
357         ( iternextfunc ) KX_PythonSeq_nextIter, /* iternextfunc tp_iternext; */
358
359   /*** Attribute descriptor and subclassing stuff ***/
360         NULL,       /* struct PyMethodDef *tp_methods; */
361         NULL,                       /* struct PyMemberDef *tp_members; */
362         NULL,       /* struct PyGetSetDef *tp_getset; */
363         NULL,                       /* struct _typeobject *tp_base; */
364         NULL,                       /* PyObject *tp_dict; */
365         NULL,                       /* descrgetfunc tp_descr_get; */
366         NULL,                       /* descrsetfunc tp_descr_set; */
367         0,                          /* long tp_dictoffset; */
368         NULL,                       /* initproc tp_init; */
369         NULL,                       /* allocfunc tp_alloc; */
370         NULL,                       /* newfunc tp_new; */
371         /*  Low-level free-memory routine */
372         NULL,                       /* freefunc tp_free;  */
373         /* For PyObject_IS_GC */
374         NULL,                       /* inquiry tp_is_gc;  */
375         NULL,                       /* PyObject *tp_bases; */
376         /* method resolution order */
377         NULL,                       /* PyObject *tp_mro;  */
378         NULL,                       /* PyObject *tp_cache; */
379         NULL,                       /* PyObject *tp_subclasses; */
380         NULL,                       /* PyObject *tp_weaklist; */
381         NULL
382 };