Blender V2.61 - r43446
|
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