Blender V2.61 - r43446

ListValue.cpp

Go to the documentation of this file.
00001 
00004 // ListValue.cpp: implementation of the CListValue class.
00005 //
00007 /*
00008  * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
00009  *
00010  * Permission to use, copy, modify, distribute and sell this software
00011  * and its documentation for any purpose is hereby granted without fee,
00012  * provided that the above copyright notice appear in all copies and
00013  * that both that copyright notice and this permission notice appear
00014  * in supporting documentation.  Erwin Coumans makes no
00015  * representations about the suitability of this software for any
00016  * purpose.  It is provided "as is" without express or implied warranty.
00017  *
00018  */
00019 
00020 #include <stdio.h>
00021 
00022 #include "ListValue.h"
00023 #include "StringValue.h"
00024 #include "VoidValue.h"
00025 #include <algorithm>
00026 #include "BoolValue.h"
00027 
00028 #include "BLO_sys_types.h" /* for intptr_t support */
00029 
00030 
00032 // Construction/Destruction
00034 
00035 CListValue::CListValue()
00036 : CPropValue()
00037 {
00038     m_bReleaseContents=true;
00039 }
00040 
00041 
00042 
00043 CListValue::~CListValue()
00044 {
00045 
00046     if (m_bReleaseContents) {
00047         for (unsigned int i=0;i<m_pValueArray.size();i++) {
00048             m_pValueArray[i]->Release();
00049         }
00050     }
00051 }
00052 
00053 
00054 static STR_String gstrListRep=STR_String("List");
00055 
00056 const STR_String & CListValue::GetText()
00057 {
00058     gstrListRep = "[";
00059     STR_String commastr = "";
00060 
00061     for (int i=0;i<GetCount();i++)
00062     {
00063         gstrListRep += commastr;
00064         gstrListRep += GetValue(i)->GetText();
00065         commastr = ",";
00066     }
00067     gstrListRep += "]";
00068 
00069     return gstrListRep;
00070 }
00071 
00072 
00073 
00074 CValue* CListValue::GetReplica() {
00075     CListValue* replica = new CListValue(*this);
00076 
00077     replica->ProcessReplica();
00078 
00079     replica->m_bReleaseContents=true; // for copy, complete array is copied for now...
00080     // copy all values
00081     int numelements = m_pValueArray.size();
00082     unsigned int i=0;
00083     replica->m_pValueArray.resize(numelements);
00084     for (i=0;i<m_pValueArray.size();i++)
00085         replica->m_pValueArray[i] = m_pValueArray[i]->GetReplica();
00086 
00087 
00088     return replica;
00089 };
00090 
00091 
00092 
00093 void CListValue::SetValue(int i, CValue *val)
00094 {
00095     assertd(i < m_pValueArray.size());
00096     m_pValueArray[i]=val;
00097 }
00098 
00099 
00100 
00101 void CListValue::Resize(int num)
00102 {
00103     m_pValueArray.resize(num);
00104 }
00105 
00106 
00107 
00108 void CListValue::Remove(int i)
00109 {
00110     assertd(i<m_pValueArray.size());
00111     m_pValueArray.erase(m_pValueArray.begin()+i);
00112 }
00113 
00114 
00115 
00116 void CListValue::ReleaseAndRemoveAll()
00117 {
00118     for (unsigned int i=0;i<m_pValueArray.size();i++)
00119         m_pValueArray[i]->Release();
00120     m_pValueArray.clear();//.Clear();
00121 }
00122 
00123 
00124 
00125 CValue* CListValue::FindValue(const STR_String & name)
00126 {
00127     for (int i=0; i < GetCount(); i++)
00128         if (GetValue(i)->GetName() == name)
00129             return GetValue(i);
00130 
00131     return NULL;
00132 }
00133 
00134 CValue* CListValue::FindValue(const char * name)
00135 {
00136     for (int i=0; i < GetCount(); i++)
00137         if (GetValue(i)->GetName() == name)
00138             return GetValue(i);
00139 
00140     return NULL;
00141 }
00142 
00143 bool CListValue::SearchValue(CValue *val)
00144 {
00145     for (int i=0;i<GetCount();i++)
00146         if (val == GetValue(i))
00147             return true;
00148     return false;
00149 }
00150 
00151 
00152 
00153 void CListValue::SetReleaseOnDestruct(bool bReleaseContents)
00154 {
00155     m_bReleaseContents = bReleaseContents;
00156 }
00157 
00158 
00159 
00160 bool CListValue::RemoveValue(CValue *val)
00161 {
00162     bool result=false;
00163 
00164     for (int i=GetCount()-1;i>=0;i--)
00165         if (val == GetValue(i))
00166         {
00167             Remove(i);
00168             result=true;
00169         }
00170     return result;
00171 }
00172 
00173 
00174 
00175 void CListValue::MergeList(CListValue *otherlist)
00176 {
00177 
00178     int numelements = this->GetCount();
00179     int numotherelements = otherlist->GetCount();
00180 
00181 
00182     Resize(numelements+numotherelements);
00183 
00184     for (int i=0;i<numotherelements;i++)
00185     {
00186         SetValue(i+numelements,otherlist->GetValue(i)->AddRef());
00187     }
00188 }
00189 
00190 bool CListValue::CheckEqual(CValue* first,CValue* second)
00191 {
00192     bool result = false;
00193 
00194     CValue* eqval =  ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second);
00195 
00196     if (eqval==NULL)
00197         return false;
00198     const STR_String& text = eqval->GetText();
00199     if (&text==&CBoolValue::sTrueString)
00200     {
00201         result = true;
00202     }
00203     eqval->Release();
00204     return result;
00205 
00206 }
00207 
00208 
00209 /* ---------------------------------------------------------------------
00210  * Some stuff taken from the header
00211  * --------------------------------------------------------------------- */
00212 CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val)
00213 {
00214     //assert(false); // todo: implement me!
00215     static int error_printed =  0;
00216     if (error_printed==0) {
00217         fprintf(stderr, "CValueList::Calc not yet implimented\n");
00218         error_printed = 1;
00219     }
00220     return NULL;
00221 }
00222 
00223 CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype,
00224                               VALUE_OPERATOR op,
00225                               CValue* val)
00226 {
00227     //assert(false); // todo: implement me!
00228     static int error_printed =  0;
00229     if (error_printed==0) {
00230         fprintf(stderr, "CValueList::CalcFinal not yet implimented\n");
00231         error_printed = 1;
00232     }
00233     return NULL;
00234 }
00235 
00236 
00237 
00238 void CListValue::Add(CValue* value)
00239 {
00240     m_pValueArray.push_back(value);
00241 }
00242 
00243 
00244 
00245 double CListValue::GetNumber()
00246 {
00247     return -1;
00248 }
00249 
00250 
00251 
00252 void CListValue::SetModified(bool bModified)
00253 {
00254     CValue::SetModified(bModified);
00255     int numels = GetCount();
00256 
00257     for (int i=0;i<numels;i++)
00258         GetValue(i)->SetModified(bModified);
00259 }
00260 
00261 
00262 
00263 bool CListValue::IsModified()
00264 {
00265     bool bmod = CValue::IsModified(); //normal own flag
00266     int numels = GetCount();
00267 
00268     for (int i=0;i<numels;i++)
00269         bmod = bmod || GetValue(i)->IsModified();
00270 
00271     return bmod;
00272 }
00273 
00274 #ifdef WITH_PYTHON
00275 
00276 /* --------------------------------------------------------------------- */
00277 /* Python interface ---------------------------------------------------- */
00278 /* --------------------------------------------------------------------- */
00279 
00280 Py_ssize_t listvalue_bufferlen(PyObject* self)
00281 {
00282     CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
00283     if (list==NULL)
00284         return 0;
00285     
00286     return (Py_ssize_t)list->GetCount();
00287 }
00288 
00289 PyObject* listvalue_buffer_item(PyObject* self, Py_ssize_t index)
00290 {
00291     CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
00292     CValue *cval;
00293     
00294     if (list==NULL) {
00295         PyErr_SetString(PyExc_SystemError, "val = CList[i], "BGE_PROXY_ERROR_MSG);
00296         return NULL;
00297     }
00298     
00299     int count = list->GetCount();
00300     
00301     if (index < 0)
00302         index = count+index;
00303     
00304     if (index < 0 || index >= count) {
00305         PyErr_SetString(PyExc_IndexError, "CList[i]: Python ListIndex out of range in CValueList");
00306         return NULL;
00307     }
00308     
00309     cval= list->GetValue(index);
00310     
00311     PyObject* pyobj = cval->ConvertValueToPython();
00312     if (pyobj)
00313         return pyobj;
00314     else
00315         return cval->GetProxy();
00316 }
00317 
00318 PyObject* listvalue_mapping_subscript(PyObject* self, PyObject* pyindex)
00319 {
00320     CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
00321     if (list==NULL) {
00322         PyErr_SetString(PyExc_SystemError, "value = CList[i], "BGE_PROXY_ERROR_MSG);
00323         return NULL;
00324     }
00325     
00326     if (PyUnicode_Check(pyindex))
00327     {
00328         CValue *item = ((CListValue*) list)->FindValue(_PyUnicode_AsString(pyindex));
00329         if (item) {
00330             PyObject* pyobj = item->ConvertValueToPython();
00331             if(pyobj)
00332                 return pyobj;
00333             else
00334                 return item->GetProxy();
00335         }
00336     }
00337     else if (PyLong_Check(pyindex))
00338     {
00339         int index = PyLong_AsSsize_t(pyindex);
00340         return listvalue_buffer_item(self, index); /* wont add a ref */
00341     }
00342 
00343     PyErr_Format(PyExc_KeyError,
00344                  "CList[key]: '%R' key not in list", pyindex);
00345     return NULL;
00346 }
00347 
00348 
00349 /* just slice it into a python list... */
00350 PyObject* listvalue_buffer_slice(PyObject* self,Py_ssize_t ilow, Py_ssize_t ihigh)
00351 {
00352     CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
00353     if (list==NULL) {
00354         PyErr_SetString(PyExc_SystemError, "val = CList[i:j], "BGE_PROXY_ERROR_MSG);
00355         return NULL;
00356     }
00357     
00358     int i, j;
00359     PyObject *newlist;
00360 
00361     if (ilow < 0) ilow = 0;
00362 
00363     int n = ((CListValue*) list)->GetCount();
00364 
00365     if (ihigh >= n)
00366         ihigh = n;
00367     if (ihigh < ilow)
00368         ihigh = ilow;
00369 
00370     newlist = PyList_New(ihigh - ilow);
00371     if (!newlist)
00372         return NULL;
00373 
00374     for (i = ilow, j = 0; i < ihigh; i++, j++)
00375     {
00376         PyObject* pyobj = list->GetValue(i)->ConvertValueToPython();
00377         if (!pyobj)
00378             pyobj = list->GetValue(i)->GetProxy();
00379         PyList_SET_ITEM(newlist, i, pyobj);
00380     }   
00381     return newlist;
00382 }
00383 
00384 
00385 /* clist + list, return a list that python owns */
00386 static PyObject *listvalue_buffer_concat(PyObject * self, PyObject * other)
00387 {
00388     CListValue *listval= static_cast<CListValue *>(BGE_PROXY_REF(self));
00389     Py_ssize_t i, numitems, numitems_orig;
00390     
00391     if (listval==NULL) {
00392         PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG);
00393         return NULL;
00394     }
00395     
00396     numitems_orig= listval->GetCount();
00397     
00398     // for now, we support CListValue concatenated with items
00399     // and CListValue concatenated to Python Lists
00400     // and CListValue concatenated with another CListValue
00401     
00402     /* Shallow copy, dont use listval->GetReplica(), it will screw up with KX_GameObjects */
00403     CListValue* listval_new = new CListValue();
00404     
00405     if (PyList_Check(other))
00406     {
00407         CValue* listitemval;
00408         bool error = false;
00409         
00410         numitems = PyList_GET_SIZE(other);
00411         
00412         /* copy the first part of the list */
00413         listval_new->Resize(numitems_orig + numitems);
00414         for (i=0;i<numitems_orig;i++)
00415             listval_new->SetValue(i, listval->GetValue(i)->AddRef());
00416         
00417         for (i=0;i<numitems;i++)
00418         {
00419             listitemval = listval->ConvertPythonToValue(PyList_GetItem(other,i), "cList + pyList: CListValue, ");
00420             
00421             if (listitemval) {
00422                 listval_new->SetValue(i+numitems_orig, listitemval);
00423             } else {
00424                 error= true;
00425                 break;
00426             }
00427         }
00428         
00429         if (error) {
00430             listval_new->Resize(numitems_orig+i); /* resize so we dont try release NULL pointers */
00431             listval_new->Release();
00432             return NULL; /* ConvertPythonToValue above sets the error */ 
00433         }
00434     
00435     }
00436     else if (PyObject_TypeCheck(other, &CListValue::Type)) {
00437         // add items from otherlist to this list
00438         CListValue* otherval = static_cast<CListValue *>(BGE_PROXY_REF(other));
00439         if(otherval==NULL) {
00440             listval_new->Release();
00441             PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG);
00442             return NULL;
00443         }
00444         
00445         numitems = otherval->GetCount();
00446         
00447         /* copy the first part of the list */
00448         listval_new->Resize(numitems_orig + numitems); /* resize so we dont try release NULL pointers */
00449         for (i=0;i<numitems_orig;i++)
00450             listval_new->SetValue(i, listval->GetValue(i)->AddRef());
00451         
00452         /* now copy the other part of the list */
00453         for (i=0;i<numitems;i++)
00454             listval_new->SetValue(i+numitems_orig, otherval->GetValue(i)->AddRef());
00455         
00456     }
00457     return listval_new->NewProxy(true); /* python owns this list */
00458 }
00459 
00460 static int listvalue_buffer_contains(PyObject *self_v, PyObject *value)
00461 {
00462     CListValue *self= static_cast<CListValue *>(BGE_PROXY_REF(self_v));
00463     
00464     if (self==NULL) {
00465         PyErr_SetString(PyExc_SystemError, "val in CList, "BGE_PROXY_ERROR_MSG);
00466         return -1;
00467     }
00468     
00469     if (PyUnicode_Check(value)) {
00470         if (self->FindValue((const char *)_PyUnicode_AsString(value))) {
00471             return 1;
00472         }
00473     }
00474     else if (PyObject_TypeCheck(value, &CValue::Type)) { /* not dict like at all but this worked before __contains__ was used */
00475         CValue *item= static_cast<CValue *>(BGE_PROXY_REF(value));
00476         for (int i=0; i < self->GetCount(); i++)
00477             if (self->GetValue(i) == item) // Com
00478                 return 1;
00479         
00480     } // not using CheckEqual
00481     
00482     return 0;
00483 }
00484 
00485 
00486 static  PySequenceMethods listvalue_as_sequence = {
00487     listvalue_bufferlen,//(inquiry)buffer_length, /*sq_length*/
00488     listvalue_buffer_concat, /*sq_concat*/
00489     NULL, /*sq_repeat*/
00490     listvalue_buffer_item, /*sq_item*/
00491 // TODO, slicing in py3
00492     NULL, // listvalue_buffer_slice, /*sq_slice*/
00493     NULL, /*sq_ass_item*/
00494     NULL, /*sq_ass_slice*/
00495     (objobjproc)listvalue_buffer_contains,  /* sq_contains */
00496     (binaryfunc) NULL, /* sq_inplace_concat */
00497     (ssizeargfunc) NULL, /* sq_inplace_repeat */
00498 };
00499 
00500 
00501 
00502 /* Is this one used ? */
00503 static  PyMappingMethods instance_as_mapping = {
00504     listvalue_bufferlen, /*mp_length*/
00505     listvalue_mapping_subscript, /*mp_subscript*/
00506     NULL /*mp_ass_subscript*/
00507 };
00508 
00509 
00510 
00511 PyTypeObject CListValue::Type = {
00512     PyVarObject_HEAD_INIT(NULL, 0)
00513     "CListValue",           /*tp_name*/
00514     sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/
00515     0,              /*tp_itemsize*/
00516     /* methods */
00517     py_base_dealloc,            /*tp_dealloc*/
00518     0,              /*tp_print*/
00519     0,          /*tp_getattr*/
00520     0,          /*tp_setattr*/
00521     0,          /*tp_compare*/
00522     py_base_repr, /*tp_repr*/
00523     0,                  /*tp_as_number*/
00524     &listvalue_as_sequence, /*tp_as_sequence*/
00525     &instance_as_mapping,           /*tp_as_mapping*/
00526     0,                  /*tp_hash*/
00527     0,              /*tp_call */
00528     0,
00529     NULL,
00530     NULL,
00531     0,
00532     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00533     0,0,0,0,0,0,0,
00534     Methods,
00535     0,
00536     0,
00537     &CValue::Type,
00538     0,0,0,0,0,0,
00539     py_base_new
00540 };
00541 
00542 PyMethodDef CListValue::Methods[] = {
00543     /* List style access */
00544     {"append", (PyCFunction)CListValue::sPyappend,METH_O},
00545     {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS},
00546     {"index", (PyCFunction)CListValue::sPyindex,METH_O},
00547     {"count", (PyCFunction)CListValue::sPycount,METH_O},
00548 
00549     /* Dict style access */
00550     {"get", (PyCFunction)CListValue::sPyget,METH_VARARGS},
00551 
00552     /* Own cvalue funcs */
00553     {"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O},
00554 
00555     {NULL,NULL} //Sentinel
00556 };
00557 
00558 PyAttributeDef CListValue::Attributes[] = {
00559     { NULL }    //Sentinel
00560 };
00561 
00562 PyObject* CListValue::Pyappend(PyObject* value)
00563 {
00564     CValue* objval = ConvertPythonToValue(value, "CList.append(i): CValueList, ");
00565 
00566     if (!objval) /* ConvertPythonToValue sets the error */
00567         return NULL;
00568 
00569     if (!BGE_PROXY_PYOWNS(m_proxy)) {
00570         PyErr_SetString(PyExc_TypeError, "CList.append(i): this CValueList is used internally for the game engine and can't be modified");
00571         return NULL;
00572     }
00573 
00574     Add(objval);
00575 
00576     Py_RETURN_NONE;
00577 }
00578 
00579 PyObject* CListValue::Pyreverse()
00580 {
00581     std::reverse(m_pValueArray.begin(),m_pValueArray.end());
00582     Py_RETURN_NONE;
00583 }
00584 
00585 PyObject* CListValue::Pyindex(PyObject *value)
00586 {
00587     PyObject* result = NULL;
00588 
00589     CValue* checkobj = ConvertPythonToValue(value, "val = cList[i]: CValueList, ");
00590     if (checkobj==NULL)
00591         return NULL; /* ConvertPythonToValue sets the error */
00592 
00593     int numelem = GetCount();
00594     for (int i=0;i<numelem;i++)
00595     {
00596         CValue* elem =          GetValue(i);
00597         if (checkobj==elem || CheckEqual(checkobj,elem))
00598         {
00599             result = PyLong_FromSsize_t(i);
00600             break;
00601         }
00602     }
00603     checkobj->Release();
00604 
00605     if (result==NULL) {
00606         PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in CListValue");
00607     }
00608     return result;
00609 
00610 }
00611 
00612 
00613 
00614 PyObject* CListValue::Pycount(PyObject* value)
00615 {
00616     int numfound = 0;
00617 
00618     CValue* checkobj = ConvertPythonToValue(value, ""); /* error ignored */
00619 
00620     if (checkobj==NULL) { /* in this case just return that there are no items in the list */
00621         PyErr_Clear();
00622         return PyLong_FromSsize_t(0);
00623     }
00624 
00625     int numelem = GetCount();
00626     for (int i=0;i<numelem;i++)
00627     {
00628         CValue* elem =          GetValue(i);
00629         if (checkobj==elem || CheckEqual(checkobj,elem))
00630         {
00631             numfound ++;
00632         }
00633     }
00634     checkobj->Release();
00635 
00636     return PyLong_FromSsize_t(numfound);
00637 }
00638 
00639 /* Matches python dict.get(key, [default]) */
00640 PyObject* CListValue::Pyget(PyObject *args)
00641 {
00642     char *key;
00643     PyObject* def = Py_None;
00644 
00645     if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
00646         return NULL;
00647 
00648     CValue *item = FindValue((const char *)key);
00649     if (item) {
00650         PyObject* pyobj = item->ConvertValueToPython();
00651         if (pyobj)
00652             return pyobj;
00653         else
00654             return item->GetProxy();
00655     }
00656     Py_INCREF(def);
00657     return def;
00658 }
00659 
00660 
00661 PyObject* CListValue::Pyfrom_id(PyObject* value)
00662 {
00663     uintptr_t id= (uintptr_t)PyLong_AsVoidPtr(value);
00664 
00665     if (PyErr_Occurred())
00666         return NULL;
00667 
00668     int numelem = GetCount();
00669     for (int i=0;i<numelem;i++)
00670     {
00671         if (reinterpret_cast<uintptr_t>(m_pValueArray[i]->m_proxy) == id)
00672             return GetValue(i)->GetProxy();
00673     }
00674     PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in CValueList");
00675     return NULL;
00676 
00677 }
00678 
00679 #endif // WITH_PYTHON