Blender  V2.59
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         PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */
00344         PyErr_Format(PyExc_KeyError, "CList[key]: '%s' key not in list", _PyUnicode_AsString(pyindex_str));
00345         Py_DECREF(pyindex_str);
00346         return NULL;
00347 }
00348 
00349 
00350 /* just slice it into a python list... */
00351 PyObject* listvalue_buffer_slice(PyObject* self,Py_ssize_t ilow, Py_ssize_t ihigh)
00352 {
00353         CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
00354         if (list==NULL) {
00355                 PyErr_SetString(PyExc_SystemError, "val = CList[i:j], "BGE_PROXY_ERROR_MSG);
00356                 return NULL;
00357         }
00358         
00359         int i, j;
00360         PyObject *newlist;
00361 
00362         if (ilow < 0) ilow = 0;
00363 
00364         int n = ((CListValue*) list)->GetCount();
00365 
00366         if (ihigh >= n)
00367                 ihigh = n;
00368         if (ihigh < ilow)
00369                 ihigh = ilow;
00370 
00371         newlist = PyList_New(ihigh - ilow);
00372         if (!newlist)
00373                 return NULL;
00374 
00375         for (i = ilow, j = 0; i < ihigh; i++, j++)
00376         {
00377                 PyObject* pyobj = list->GetValue(i)->ConvertValueToPython();
00378                 if (!pyobj)
00379                         pyobj = list->GetValue(i)->GetProxy();
00380                 PyList_SET_ITEM(newlist, i, pyobj);
00381         }       
00382         return newlist;
00383 }
00384 
00385 
00386 /* clist + list, return a list that python owns */
00387 static PyObject *listvalue_buffer_concat(PyObject * self, PyObject * other)
00388 {
00389         CListValue *listval= static_cast<CListValue *>(BGE_PROXY_REF(self));
00390         int i, numitems, numitems_orig;
00391         
00392         if (listval==NULL) {
00393                 PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG);
00394                 return NULL;
00395         }
00396         
00397         numitems_orig= listval->GetCount();
00398         
00399         // for now, we support CListValue concatenated with items
00400         // and CListValue concatenated to Python Lists
00401         // and CListValue concatenated with another CListValue
00402         
00403         /* Shallow copy, dont use listval->GetReplica(), it will screw up with KX_GameObjects */
00404         CListValue* listval_new = new CListValue();
00405         
00406         if (PyList_Check(other))
00407         {
00408                 CValue* listitemval;
00409                 bool error = false;
00410                 
00411                 numitems = PyList_Size(other);
00412                 
00413                 /* copy the first part of the list */
00414                 listval_new->Resize(numitems_orig + numitems);
00415                 for (i=0;i<numitems_orig;i++)
00416                         listval_new->SetValue(i, listval->GetValue(i)->AddRef());
00417                 
00418                 for (i=0;i<numitems;i++)
00419                 {
00420                         listitemval = listval->ConvertPythonToValue(PyList_GetItem(other,i), "cList + pyList: CListValue, ");
00421                         
00422                         if (listitemval) {
00423                                 listval_new->SetValue(i+numitems_orig, listitemval);
00424                         } else {
00425                                 error= true;
00426                                 break;
00427                         }
00428                 }
00429                 
00430                 if (error) {
00431                         listval_new->Resize(numitems_orig+i); /* resize so we dont try release NULL pointers */
00432                         listval_new->Release();
00433                         return NULL; /* ConvertPythonToValue above sets the error */ 
00434                 }
00435         
00436         }
00437         else if (PyObject_TypeCheck(other, &CListValue::Type)) {
00438                 // add items from otherlist to this list
00439                 CListValue* otherval = static_cast<CListValue *>(BGE_PROXY_REF(other));
00440                 if(otherval==NULL) {
00441                         listval_new->Release();
00442                         PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG);
00443                         return NULL;
00444                 }
00445                 
00446                 numitems = otherval->GetCount();
00447                 
00448                 /* copy the first part of the list */
00449                 listval_new->Resize(numitems_orig + numitems); /* resize so we dont try release NULL pointers */
00450                 for (i=0;i<numitems_orig;i++)
00451                         listval_new->SetValue(i, listval->GetValue(i)->AddRef());
00452                 
00453                 /* now copy the other part of the list */
00454                 for (i=0;i<numitems;i++)
00455                         listval_new->SetValue(i+numitems_orig, otherval->GetValue(i)->AddRef());
00456                 
00457         }
00458         return listval_new->NewProxy(true); /* python owns this list */
00459 }
00460 
00461 static int listvalue_buffer_contains(PyObject *self_v, PyObject *value)
00462 {
00463         CListValue *self= static_cast<CListValue *>(BGE_PROXY_REF(self_v));
00464         
00465         if (self==NULL) {
00466                 PyErr_SetString(PyExc_SystemError, "val in CList, "BGE_PROXY_ERROR_MSG);
00467                 return -1;
00468         }
00469         
00470         if (PyUnicode_Check(value)) {
00471                 if (self->FindValue((const char *)_PyUnicode_AsString(value))) {
00472                         return 1;
00473                 }
00474         }
00475         else if (PyObject_TypeCheck(value, &CValue::Type)) { /* not dict like at all but this worked before __contains__ was used */
00476                 CValue *item= static_cast<CValue *>(BGE_PROXY_REF(value));
00477                 for (int i=0; i < self->GetCount(); i++)
00478                         if (self->GetValue(i) == item) // Com
00479                                 return 1;
00480                 
00481         } // not using CheckEqual
00482         
00483         return 0;
00484 }
00485 
00486 
00487 static  PySequenceMethods listvalue_as_sequence = {
00488         listvalue_bufferlen,//(inquiry)buffer_length, /*sq_length*/
00489         listvalue_buffer_concat, /*sq_concat*/
00490         NULL, /*sq_repeat*/
00491         listvalue_buffer_item, /*sq_item*/
00492 // TODO, slicing in py3
00493         NULL, // listvalue_buffer_slice, /*sq_slice*/
00494         NULL, /*sq_ass_item*/
00495         NULL, /*sq_ass_slice*/
00496         (objobjproc)listvalue_buffer_contains,  /* sq_contains */
00497         (binaryfunc) NULL, /* sq_inplace_concat */
00498         (ssizeargfunc) NULL, /* sq_inplace_repeat */
00499 };
00500 
00501 
00502 
00503 /* Is this one used ? */
00504 static  PyMappingMethods instance_as_mapping = {
00505         listvalue_bufferlen, /*mp_length*/
00506         listvalue_mapping_subscript, /*mp_subscript*/
00507         NULL /*mp_ass_subscript*/
00508 };
00509 
00510 
00511 
00512 PyTypeObject CListValue::Type = {
00513         PyVarObject_HEAD_INIT(NULL, 0)
00514         "CListValue",                   /*tp_name*/
00515         sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/
00516         0,                              /*tp_itemsize*/
00517         /* methods */
00518         py_base_dealloc,                        /*tp_dealloc*/
00519         0,                              /*tp_print*/
00520         0,                      /*tp_getattr*/
00521         0,                      /*tp_setattr*/
00522         0,                              /*tp_compare*/
00523         py_base_repr,                           /*tp_repr*/
00524         0,                              /*tp_as_number*/
00525         &listvalue_as_sequence, /*tp_as_sequence*/
00526         &instance_as_mapping,           /*tp_as_mapping*/
00527         0,                              /*tp_hash*/
00528         0,                              /*tp_call */
00529         0,
00530         NULL,
00531         NULL,
00532         0,
00533         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00534         0,0,0,0,0,0,0,
00535         Methods,
00536         0,
00537         0,
00538         &CValue::Type,
00539         0,0,0,0,0,0,
00540         py_base_new
00541 };
00542 
00543 PyMethodDef CListValue::Methods[] = {
00544         /* List style access */
00545         {"append", (PyCFunction)CListValue::sPyappend,METH_O},
00546         {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS},
00547         {"index", (PyCFunction)CListValue::sPyindex,METH_O},
00548         {"count", (PyCFunction)CListValue::sPycount,METH_O},
00549 
00550         /* Dict style access */
00551         {"get", (PyCFunction)CListValue::sPyget,METH_VARARGS},
00552 
00553         /* Own cvalue funcs */
00554         {"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O},
00555 
00556         {NULL,NULL} //Sentinel
00557 };
00558 
00559 PyAttributeDef CListValue::Attributes[] = {
00560         { NULL }        //Sentinel
00561 };
00562 
00563 PyObject* CListValue::Pyappend(PyObject* value)
00564 {
00565         CValue* objval = ConvertPythonToValue(value, "CList.append(i): CValueList, ");
00566 
00567         if (!objval) /* ConvertPythonToValue sets the error */
00568                 return NULL;
00569 
00570         if (!BGE_PROXY_PYOWNS(m_proxy)) {
00571                 PyErr_SetString(PyExc_TypeError, "CList.append(i): this CValueList is used internally for the game engine and can't be modified");
00572                 return NULL;
00573         }
00574 
00575         Add(objval);
00576 
00577         Py_RETURN_NONE;
00578 }
00579 
00580 PyObject* CListValue::Pyreverse()
00581 {
00582         std::reverse(m_pValueArray.begin(),m_pValueArray.end());
00583         Py_RETURN_NONE;
00584 }
00585 
00586 PyObject* CListValue::Pyindex(PyObject *value)
00587 {
00588         PyObject* result = NULL;
00589 
00590         CValue* checkobj = ConvertPythonToValue(value, "val = cList[i]: CValueList, ");
00591         if (checkobj==NULL)
00592                 return NULL; /* ConvertPythonToValue sets the error */
00593 
00594         int numelem = GetCount();
00595         for (int i=0;i<numelem;i++)
00596         {
00597                 CValue* elem =                  GetValue(i);
00598                 if (checkobj==elem || CheckEqual(checkobj,elem))
00599                 {
00600                         result = PyLong_FromSsize_t(i);
00601                         break;
00602                 }
00603         }
00604         checkobj->Release();
00605 
00606         if (result==NULL) {
00607                 PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in CListValue");
00608         }
00609         return result;
00610 
00611 }
00612 
00613 
00614 
00615 PyObject* CListValue::Pycount(PyObject* value)
00616 {
00617         int numfound = 0;
00618 
00619         CValue* checkobj = ConvertPythonToValue(value, ""); /* error ignored */
00620 
00621         if (checkobj==NULL) { /* in this case just return that there are no items in the list */
00622                 PyErr_Clear();
00623                 return PyLong_FromSsize_t(0);
00624         }
00625 
00626         int numelem = GetCount();
00627         for (int i=0;i<numelem;i++)
00628         {
00629                 CValue* elem =                  GetValue(i);
00630                 if (checkobj==elem || CheckEqual(checkobj,elem))
00631                 {
00632                         numfound ++;
00633                 }
00634         }
00635         checkobj->Release();
00636 
00637         return PyLong_FromSsize_t(numfound);
00638 }
00639 
00640 /* Matches python dict.get(key, [default]) */
00641 PyObject* CListValue::Pyget(PyObject *args)
00642 {
00643         char *key;
00644         PyObject* def = Py_None;
00645 
00646         if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
00647                 return NULL;
00648 
00649         CValue *item = FindValue((const char *)key);
00650         if (item) {
00651                 PyObject* pyobj = item->ConvertValueToPython();
00652                 if (pyobj)
00653                         return pyobj;
00654                 else
00655                         return item->GetProxy();
00656         }
00657         Py_INCREF(def);
00658         return def;
00659 }
00660 
00661 
00662 PyObject* CListValue::Pyfrom_id(PyObject* value)
00663 {
00664         uintptr_t id= (uintptr_t)PyLong_AsVoidPtr(value);
00665 
00666         if (PyErr_Occurred())
00667                 return NULL;
00668 
00669         int numelem = GetCount();
00670         for (int i=0;i<numelem;i++)
00671         {
00672                 if (reinterpret_cast<uintptr_t>(m_pValueArray[i]->m_proxy) == id)
00673                         return GetValue(i)->GetProxy();
00674         }
00675         PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in CValueList");
00676         return NULL;
00677 
00678 }
00679 
00680 #endif // WITH_PYTHON