Blender  V2.59
KX_PythonSeq.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: KX_PythonSeq.cpp 35211 2011-02-27 03:59:17Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: none of this file.
00024  *
00025  * Contributor(s): Campbell Barton
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  * Readonly sequence wrapper for lookups on logic bricks
00029  */
00030 
00036 #ifdef WITH_PYTHON
00037 
00038 #include "KX_PythonSeq.h"
00039 #include "KX_GameObject.h"
00040 #include "BL_ArmatureObject.h"
00041 #include "SCA_ISensor.h"
00042 #include "SCA_IController.h"
00043 #include "SCA_IActuator.h"
00044 
00045 
00046 PyObject *KX_PythonSeq_CreatePyObject( PyObject *base, short type )
00047 {
00048         KX_PythonSeq *seq = PyObject_GC_New(KX_PythonSeq, &KX_PythonSeq_Type);
00049         seq->base = base;
00050         Py_INCREF(base); /* so we can always access to check if its valid */
00051         seq->type = type;
00052         seq->iter = -1; /* init */
00053         return (PyObject *)seq;
00054 }
00055 
00056 static int KX_PythonSeq_traverse(KX_PythonSeq *self, visitproc visit, void *arg)
00057 {
00058         Py_VISIT(self->base);
00059         return 0;
00060 }
00061 
00062 static int KX_PythonSeq_clear(KX_PythonSeq *self)
00063 {
00064         Py_CLEAR(self->base);
00065         return 0;
00066 }
00067 
00068 static void KX_PythonSeq_dealloc(KX_PythonSeq * self)
00069 {
00070         KX_PythonSeq_clear(self);
00071         PyObject_GC_Del(self);
00072 }
00073 
00074 static Py_ssize_t KX_PythonSeq_len( PyObject * self )
00075 {
00076         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
00077          
00078         if(self_plus==NULL) {
00079                 PyErr_SetString(PyExc_SystemError, "len(seq): "BGE_PROXY_ERROR_MSG);
00080                 return -1;
00081         }
00082         
00083         switch(((KX_PythonSeq *)self)->type) {
00084         case KX_PYGENSEQ_CONT_TYPE_SENSORS:
00085                 return ((SCA_IController *)self_plus)->GetLinkedSensors().size();
00086         case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
00087                 return ((SCA_IController *)self_plus)->GetLinkedActuators().size();
00088         case KX_PYGENSEQ_OB_TYPE_SENSORS:
00089                 return ((KX_GameObject *)self_plus)->GetSensors().size();
00090         case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
00091                 return ((KX_GameObject *)self_plus)->GetControllers().size();
00092         case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
00093                 return ((KX_GameObject *)self_plus)->GetActuators().size();
00094         case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
00095                 return ((BL_ArmatureObject *)self_plus)->GetConstraintNumber();
00096         case KX_PYGENSEQ_OB_TYPE_CHANNELS:
00097                 return ((BL_ArmatureObject *)self_plus)->GetChannelNumber();
00098         default:
00099                 /* Should never happen */
00100                 PyErr_SetString(PyExc_SystemError, "invalid type, internal error");
00101                 return -1;
00102         }
00103 }
00104 
00105 static PyObject *KX_PythonSeq_getIndex(PyObject* self, int index)
00106 {
00107         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
00108          
00109         if(self_plus==NULL) {
00110                 PyErr_SetString(PyExc_SystemError, "val = seq[i]: "BGE_PROXY_ERROR_MSG);
00111                 return NULL;
00112         }
00113         
00114         switch(((KX_PythonSeq *)self)->type) {
00115                 case KX_PYGENSEQ_CONT_TYPE_SENSORS:
00116                 {
00117                         vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
00118                         if(index<0) index += linkedsensors.size();
00119                         if(index<0 || index>= linkedsensors.size()) {
00120                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
00121                                 return NULL;
00122                         }
00123                         return linkedsensors[index]->GetProxy();
00124                 }
00125                 case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
00126                 {
00127                         vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
00128                         if(index<0) index += linkedactuators.size();
00129                         if(index<0 || index>= linkedactuators.size()) {
00130                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
00131                                 return NULL;
00132                         }
00133                         return linkedactuators[index]->GetProxy();
00134                 }
00135                 case KX_PYGENSEQ_OB_TYPE_SENSORS:
00136                 {
00137                         SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
00138                         if(index<0) index += linkedsensors.size();
00139                         if(index<0 || index>= linkedsensors.size()) {
00140                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
00141                                 return NULL;
00142                         }
00143                         return linkedsensors[index]->GetProxy();
00144                 }
00145                 case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
00146                 {
00147                         SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
00148                         if(index<0) index += linkedcontrollers.size();
00149                         if(index<0 || index>= linkedcontrollers.size()) {
00150                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
00151                                 return NULL;
00152                         }
00153                         return linkedcontrollers[index]->GetProxy();
00154                 }
00155                 case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
00156                 {
00157                         SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
00158                         if(index<0) index += linkedactuators.size();
00159                         if(index<0 || index>= linkedactuators.size()) {
00160                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
00161                                 return NULL;
00162                         }
00163                         return linkedactuators[index]->GetProxy();
00164                 }
00165                 case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
00166                 {
00167                         int nb_constraint = ((BL_ArmatureObject *)self_plus)->GetConstraintNumber();
00168                         if(index<0) 
00169                                 index += nb_constraint;
00170                         if(index<0 || index>= nb_constraint) {
00171                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
00172                                 return NULL;
00173                         }
00174                         return ((BL_ArmatureObject *)self_plus)->GetConstraint(index)->GetProxy();
00175                 }
00176                 case KX_PYGENSEQ_OB_TYPE_CHANNELS:
00177                 {
00178                         int nb_channel = ((BL_ArmatureObject *)self_plus)->GetChannelNumber();
00179                         if(index<0) 
00180                                 index += nb_channel;
00181                         if(index<0 || index>= nb_channel) {
00182                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
00183                                 return NULL;
00184                         }
00185                         return ((BL_ArmatureObject *)self_plus)->GetChannel(index)->GetProxy();
00186                 }
00187 
00188         }
00189         
00190         PyErr_SetString(PyExc_SystemError, "invalid sequence type, this is a bug");
00191         return NULL;
00192 }
00193 
00194 static PyObjectPlus * KX_PythonSeq_subscript__internal(PyObject *self, char *key)
00195 {
00196         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
00197         
00198         switch(((KX_PythonSeq *)self)->type) {
00199                 case KX_PYGENSEQ_CONT_TYPE_SENSORS:
00200                 {
00201                         vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
00202                         SCA_ISensor* sensor;
00203                         for (unsigned int index=0;index<linkedsensors.size();index++) {
00204                                 sensor = linkedsensors[index];
00205                                 if (sensor->GetName() == key)
00206                                         return static_cast<PyObjectPlus *>(sensor);
00207                                 
00208                         }
00209                         break;
00210                 }
00211                 case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
00212                 {
00213                         vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
00214                         SCA_IActuator* actuator;
00215                         for (unsigned int index=0;index<linkedactuators.size();index++) {
00216                                 actuator = linkedactuators[index];
00217                                 if (actuator->GetName() == key)
00218                                         return static_cast<PyObjectPlus *>(actuator);
00219                         }
00220                         break;
00221                 }
00222                 case KX_PYGENSEQ_OB_TYPE_SENSORS:
00223                 {
00224                         SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
00225                         SCA_ISensor *sensor;
00226                         for (unsigned int index=0;index<linkedsensors.size();index++) {
00227                                 sensor= linkedsensors[index];
00228                                 if (sensor->GetName() == key)
00229                                         return static_cast<PyObjectPlus *>(sensor);
00230                         }
00231                         break;
00232                 }
00233                 case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
00234                 {
00235                         SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
00236                         SCA_IController *controller;
00237                         for (unsigned int index=0;index<linkedcontrollers.size();index++) {
00238                                 controller= linkedcontrollers[index];
00239                                 if (controller->GetName() == key)
00240                                         return static_cast<PyObjectPlus *>(controller);
00241                         }
00242                         break;
00243                 }
00244                 case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
00245                 {
00246                         SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
00247                         SCA_IActuator *actuator;
00248                         for (unsigned int index=0;index<linkedactuators.size();index++) {
00249                                 actuator= linkedactuators[index];
00250                                 if (actuator->GetName() == key)
00251                                         return static_cast<PyObjectPlus *>(actuator);
00252                         }
00253                         break;
00254                 }
00255                 case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
00256                 {
00257                         return ((BL_ArmatureObject*)self_plus)->GetConstraint(key);
00258                 }
00259                 case KX_PYGENSEQ_OB_TYPE_CHANNELS:
00260                 {
00261                         return ((BL_ArmatureObject*)self_plus)->GetChannel(key);
00262                 }
00263         }
00264         
00265         return NULL;
00266 }
00267 
00268 
00269 static PyObject * KX_PythonSeq_subscript(PyObject * self, PyObject *key)
00270 {
00271         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
00272         
00273         if(self_plus==NULL) {
00274                 PyErr_SetString(PyExc_SystemError, "val = seq[key], KX_PythonSeq: "BGE_PROXY_ERROR_MSG);
00275                 return NULL;
00276         }
00277         
00278         if (PyLong_Check(key)) {
00279                 return KX_PythonSeq_getIndex(self, PyLong_AsSsize_t( key ));
00280         }
00281         else if ( PyUnicode_Check(key) ) {
00282                 char *name = _PyUnicode_AsString(key);
00283                 PyObjectPlus *ret = KX_PythonSeq_subscript__internal(self, name);
00284                 
00285                 if(ret) {
00286                         return ret->GetProxy();
00287                 } else {
00288                         PyErr_Format( PyExc_KeyError, "requested item \"%s\" does not exist", name);
00289                         return NULL;
00290                 }
00291         }
00292         else {
00293                 PyErr_SetString( PyExc_TypeError, "expected a string or an index" );
00294                 return NULL;
00295         }
00296 }
00297 
00298 
00299 static int KX_PythonSeq_contains(PyObject *self, PyObject *key)
00300 {
00301         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
00302         
00303         if(self_plus==NULL) {
00304                 PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: "BGE_PROXY_ERROR_MSG);
00305                 return -1;
00306         }
00307         if(!PyUnicode_Check(key)) {
00308                 PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: key must be a string");
00309                 return -1;
00310         }
00311         
00312         if(KX_PythonSeq_subscript__internal(self, _PyUnicode_AsString(key)))
00313                 return 1;
00314         
00315         return 0;
00316 }
00317 
00318 /* Matches python dict.get(key, [default]) */
00319 PyObject* KX_PythonSeq_get(PyObject * self, PyObject *args)
00320 {
00321         char *key;
00322         PyObject* def = Py_None;
00323         PyObjectPlus* ret_plus;
00324 
00325         if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
00326                 return NULL;
00327         
00328         if((ret_plus = KX_PythonSeq_subscript__internal(self, key)))
00329                 return ret_plus->GetProxy();
00330         
00331         Py_INCREF(def);
00332         return def;
00333 }
00334 
00335 PySequenceMethods KX_PythonSeq_as_sequence = {
00336         NULL,           /* Cant set the len otherwise it can evaluate as false */
00337         NULL,           /* sq_concat */
00338         NULL,           /* sq_repeat */
00339         NULL,           /* sq_item */
00340         NULL,           /* sq_slice */
00341         NULL,           /* sq_ass_item */
00342         NULL,           /* sq_ass_slice */
00343         (objobjproc)KX_PythonSeq_contains,      /* sq_contains */
00344         (binaryfunc) NULL, /* sq_inplace_concat */
00345         (ssizeargfunc) NULL, /* sq_inplace_repeat */
00346 };
00347 
00348 static PyMappingMethods KX_PythonSeq_as_mapping = {
00349         KX_PythonSeq_len,       /* mp_length */
00350         KX_PythonSeq_subscript, /* mp_subscript */
00351         0,      /* mp_ass_subscript */
00352 };
00353 
00354 PyMethodDef KX_PythonSeq_methods[] = {
00355         // dict style access for props
00356         {"get",(PyCFunction) KX_PythonSeq_get, METH_VARARGS},
00357         {NULL,NULL} //Sentinel
00358 };
00359 
00360 /*
00361  * Initialize the interator index
00362  */
00363 
00364 static PyObject *KX_PythonSeq_getIter(KX_PythonSeq *self)
00365 {
00366         if(BGE_PROXY_REF(self->base)==NULL) {
00367                 PyErr_SetString(PyExc_SystemError, "for i in seq: "BGE_PROXY_ERROR_MSG);
00368                 return NULL;
00369         }
00370         
00371         /* create a new iterator if were already using this one */
00372         if (self->iter == -1) {
00373                 self->iter = 0;
00374                 Py_INCREF(self);
00375                 return (PyObject *)self;
00376         } else {
00377                 return KX_PythonSeq_CreatePyObject(self->base, self->type);
00378         }
00379  }
00380  
00381 
00382 /*
00383  * Return next KX_PythonSeq iter.
00384  */
00385  
00386 static PyObject *KX_PythonSeq_nextIter(KX_PythonSeq *self)
00387 {
00388         PyObject *object = KX_PythonSeq_getIndex((PyObject *)self, self->iter);
00389         
00390         self->iter++;
00391         if( object==NULL ) {
00392                 self->iter= -1; /* for reuse */
00393                 PyErr_SetString(PyExc_StopIteration,    "iterator at end");
00394         }
00395         return object; /* can be NULL for end of iterator */
00396 }
00397 
00398 
00399 static int KX_PythonSeq_compare( KX_PythonSeq * a, KX_PythonSeq * b )
00400 {
00401         return ( a->type == b->type && a->base == b->base) ? 0 : -1;    
00402 }
00403 
00404 static PyObject *KX_PythonSeq_richcmp(PyObject *a, PyObject *b, int op)
00405 {
00406         PyObject *res;
00407         int ok= -1; /* zero is true */
00408 
00409         if(BPy_KX_PythonSeq_Check(a) && BPy_KX_PythonSeq_Check(b))
00410                 ok= KX_PythonSeq_compare((KX_PythonSeq *)a, (KX_PythonSeq *)b);
00411         
00412         switch (op) {
00413         case Py_NE:
00414                 ok = !ok; /* pass through */
00415         case Py_EQ:
00416                 res = ok ? Py_False : Py_True;
00417                 break;
00418 
00419         case Py_LT:
00420         case Py_LE:
00421         case Py_GT:
00422         case Py_GE:
00423                 res = Py_NotImplemented;
00424                 break;
00425         default:
00426                 PyErr_BadArgument();
00427                 return NULL;
00428         }
00429         
00430         Py_INCREF(res);
00431         return res;
00432 }
00433 
00434 
00435 /*
00436  * repr function
00437  * convert to a list and get its string value
00438  */
00439 static PyObject *KX_PythonSeq_repr( KX_PythonSeq * self )
00440 {
00441         PyObject *list = PySequence_List((PyObject *)self);
00442         PyObject *repr = PyObject_Repr(list);
00443         Py_DECREF(list);
00444         return repr;
00445 }
00446 
00447 
00448 /*****************************************************************************/
00449 /* Python KX_PythonSeq_Type structure definition:                               */
00450 /*****************************************************************************/
00451 PyTypeObject KX_PythonSeq_Type = {
00452         PyVarObject_HEAD_INIT(NULL, 0)
00453         /*  For printing, in format "<module>.<name>" */
00454         "KX_PythonSeq",           /* char *tp_name; */
00455         sizeof( KX_PythonSeq ),       /* int tp_basicsize; */
00456         0,                          /* tp_itemsize;  For allocation */
00457 
00458         /* Methods to implement standard operations */
00459 
00460         ( destructor ) KX_PythonSeq_dealloc, /* destructor tp_dealloc; */
00461         NULL,                       /* printfunc tp_print; */
00462         NULL,                       /* getattrfunc tp_getattr; */
00463         NULL,                       /* setattrfunc tp_setattr; */
00464         NULL,                                           /* cmpfunc tp_compare; */
00465         ( reprfunc ) KX_PythonSeq_repr,   /* reprfunc tp_repr; */
00466 
00467         /* Method suites for standard classes */
00468 
00469         NULL,                       /* PyNumberMethods *tp_as_number; */
00470         &KX_PythonSeq_as_sequence,          /* PySequenceMethods *tp_as_sequence; */
00471         &KX_PythonSeq_as_mapping,                       /* PyMappingMethods *tp_as_mapping; */
00472 
00473         /* More standard operations (here for binary compatibility) */
00474 
00475         NULL,                       /* hashfunc tp_hash; */
00476         NULL,                       /* ternaryfunc tp_call; */
00477         NULL,                       /* reprfunc tp_str; */
00478         NULL,                       /* getattrofunc tp_getattro; */
00479         NULL,                       /* setattrofunc tp_setattro; */
00480 
00481         /* Functions to access object as input/output buffer */
00482         NULL,                       /* PyBufferProcs *tp_as_buffer; */
00483 
00484   /*** Flags to define presence of optional/expanded features ***/
00485         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */
00486 
00487         NULL,                       /*  char *tp_doc;  Documentation string */
00488   /*** Assigned meaning in release 2.0 ***/
00489         /* call function for all accessible objects */
00490         (traverseproc)KX_PythonSeq_traverse,    /* traverseproc tp_traverse; */
00491 
00492         /* delete references to contained objects */
00493         (inquiry)KX_PythonSeq_clear,    /* inquiry tp_clear; */
00494 
00495   /***  Assigned meaning in release 2.1 ***/
00496   /*** rich comparisons ***/
00497         (richcmpfunc)KX_PythonSeq_richcmp,      /* richcmpfunc tp_richcompare; */
00498 
00499   /***  weak reference enabler ***/
00500         0,                          /* long tp_weaklistoffset; */
00501 
00502   /*** Added in release 2.2 ***/
00503         /*   Iterators */
00504         ( getiterfunc) KX_PythonSeq_getIter, /* getiterfunc tp_iter; */
00505         ( iternextfunc ) KX_PythonSeq_nextIter, /* iternextfunc tp_iternext; */
00506 
00507   /*** Attribute descriptor and subclassing stuff ***/
00508         KX_PythonSeq_methods,       /* struct PyMethodDef *tp_methods; */
00509         NULL,                       /* struct PyMemberDef *tp_members; */
00510         NULL,       /* struct PyGetSetDef *tp_getset; */
00511         NULL,                       /* struct _typeobject *tp_base; */
00512         NULL,                       /* PyObject *tp_dict; */
00513         NULL,                       /* descrgetfunc tp_descr_get; */
00514         NULL,                       /* descrsetfunc tp_descr_set; */
00515         0,                          /* long tp_dictoffset; */
00516         NULL,                       /* initproc tp_init; */
00517         NULL,                       /* allocfunc tp_alloc; */
00518         NULL,                       /* newfunc tp_new; */
00519         /*  Low-level free-memory routine */
00520         NULL,                       /* freefunc tp_free;  */
00521         /* For PyObject_IS_GC */
00522         NULL,                       /* inquiry tp_is_gc;  */
00523         NULL,                       /* PyObject *tp_bases; */
00524         /* method resolution order */
00525         NULL,                       /* PyObject *tp_mro;  */
00526         NULL,                       /* PyObject *tp_cache; */
00527         NULL,                       /* PyObject *tp_subclasses; */
00528         NULL,                       /* PyObject *tp_weaklist; */
00529         NULL
00530 };
00531 
00532 #endif // WITH_PYTHON