Blender V2.61 - r43446

KX_PythonSeq.cpp

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