1 // ListValue.cpp: implementation of the CListValue class.
3 //////////////////////////////////////////////////////////////////////
5 * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
7 * Permission to use, copy, modify, distribute and sell this software
8 * and its documentation for any purpose is hereby granted without fee,
9 * provided that the above copyright notice appear in all copies and
10 * that both that copyright notice and this permission notice appear
11 * in supporting documentation. Erwin Coumans makes no
12 * representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
19 #include "ListValue.h"
20 #include "StringValue.h"
21 #include "VoidValue.h"
23 #include "BoolValue.h"
25 #include "BLO_sys_types.h" /* for intptr_t support */
32 //////////////////////////////////////////////////////////////////////
33 // Construction/Destruction
34 //////////////////////////////////////////////////////////////////////
36 CListValue::CListValue()
39 m_bReleaseContents=true;
44 CListValue::~CListValue()
47 if (m_bReleaseContents) {
48 for (unsigned int i=0;i<m_pValueArray.size();i++) {
49 m_pValueArray[i]->Release();
55 static STR_String gstrListRep=STR_String("List");
57 const STR_String & CListValue::GetText()
60 STR_String commastr = "";
62 for (int i=0;i<GetCount();i++)
64 gstrListRep += commastr;
65 gstrListRep += GetValue(i)->GetText();
75 CValue* CListValue::GetReplica() {
76 CListValue* replica = new CListValue(*this);
78 replica->ProcessReplica();
80 replica->m_bReleaseContents=true; // for copy, complete array is copied for now...
82 int numelements = m_pValueArray.size();
84 replica->m_pValueArray.resize(numelements);
85 for (i=0;i<m_pValueArray.size();i++)
86 replica->m_pValueArray[i] = m_pValueArray[i]->GetReplica();
94 void CListValue::SetValue(int i, CValue *val)
96 assertd(i < m_pValueArray.size());
102 void CListValue::Resize(int num)
104 m_pValueArray.resize(num);
109 void CListValue::Remove(int i)
111 assertd(i<m_pValueArray.size());
112 m_pValueArray.erase(m_pValueArray.begin()+i);
117 void CListValue::ReleaseAndRemoveAll()
119 for (unsigned int i=0;i<m_pValueArray.size();i++)
120 m_pValueArray[i]->Release();
121 m_pValueArray.clear();//.Clear();
126 CValue* CListValue::FindValue(const STR_String & name)
128 for (int i=0; i < GetCount(); i++)
129 if (GetValue(i)->GetName() == name)
135 CValue* CListValue::FindValue(const char * name)
137 for (int i=0; i < GetCount(); i++)
138 if (GetValue(i)->GetName() == name)
144 bool CListValue::SearchValue(CValue *val)
146 for (int i=0;i<GetCount();i++)
147 if (val == GetValue(i))
154 void CListValue::SetReleaseOnDestruct(bool bReleaseContents)
156 m_bReleaseContents = bReleaseContents;
161 bool CListValue::RemoveValue(CValue *val)
165 for (int i=GetCount()-1;i>=0;i--)
166 if (val == GetValue(i))
176 void CListValue::MergeList(CListValue *otherlist)
179 int numelements = this->GetCount();
180 int numotherelements = otherlist->GetCount();
183 Resize(numelements+numotherelements);
185 for (int i=0;i<numotherelements;i++)
187 SetValue(i+numelements,otherlist->GetValue(i)->AddRef());
191 bool CListValue::CheckEqual(CValue* first,CValue* second)
195 CValue* eqval = ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second);
199 const STR_String& text = eqval->GetText();
200 if (&text==&CBoolValue::sTrueString)
210 /* ---------------------------------------------------------------------
211 * Some stuff taken from the header
212 * --------------------------------------------------------------------- */
213 CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val)
215 //assert(false); // todo: implement me!
216 static int error_printed = 0;
217 if (error_printed==0) {
218 fprintf(stderr, "CValueList::Calc not yet implimented\n");
224 CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype,
228 //assert(false); // todo: implement me!
229 static int error_printed = 0;
230 if (error_printed==0) {
231 fprintf(stderr, "CValueList::CalcFinal not yet implimented\n");
239 void CListValue::Add(CValue* value)
241 m_pValueArray.push_back(value);
246 double CListValue::GetNumber()
253 void CListValue::SetModified(bool bModified)
255 CValue::SetModified(bModified);
256 int numels = GetCount();
258 for (int i=0;i<numels;i++)
259 GetValue(i)->SetModified(bModified);
264 bool CListValue::IsModified()
266 bool bmod = CValue::IsModified(); //normal own flag
267 int numels = GetCount();
269 for (int i=0;i<numels;i++)
270 bmod = bmod || GetValue(i)->IsModified();
275 #ifndef DISABLE_PYTHON
277 /* --------------------------------------------------------------------- */
278 /* Python interface ---------------------------------------------------- */
279 /* --------------------------------------------------------------------- */
281 Py_ssize_t listvalue_bufferlen(PyObject* self)
283 CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
287 return (Py_ssize_t)list->GetCount();
290 PyObject* listvalue_buffer_item(PyObject* self, Py_ssize_t index)
292 CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
296 PyErr_SetString(PyExc_SystemError, "val = CList[i], "BGE_PROXY_ERROR_MSG);
300 int count = list->GetCount();
305 if (index < 0 || index >= count) {
306 PyErr_SetString(PyExc_IndexError, "CList[i]: Python ListIndex out of range in CValueList");
310 cval= list->GetValue(index);
312 PyObject* pyobj = cval->ConvertValueToPython();
316 return cval->GetProxy();
319 PyObject* listvalue_mapping_subscript(PyObject* self, PyObject* pyindex)
321 CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
323 PyErr_SetString(PyExc_SystemError, "value = CList[i], "BGE_PROXY_ERROR_MSG);
327 if (PyUnicode_Check(pyindex))
329 CValue *item = ((CListValue*) list)->FindValue(_PyUnicode_AsString(pyindex));
331 PyObject* pyobj = item->ConvertValueToPython();
335 return item->GetProxy();
338 else if (PyLong_Check(pyindex))
340 int index = PyLong_AsSsize_t(pyindex);
341 return listvalue_buffer_item(self, index); /* wont add a ref */
344 PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */
345 PyErr_Format(PyExc_KeyError, "CList[key]: '%s' key not in list", _PyUnicode_AsString(pyindex_str));
346 Py_DECREF(pyindex_str);
351 /* just slice it into a python list... */
352 PyObject* listvalue_buffer_slice(PyObject* self,Py_ssize_t ilow, Py_ssize_t ihigh)
354 CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
356 PyErr_SetString(PyExc_SystemError, "val = CList[i:j], "BGE_PROXY_ERROR_MSG);
363 if (ilow < 0) ilow = 0;
365 int n = ((CListValue*) list)->GetCount();
372 newlist = PyList_New(ihigh - ilow);
376 for (i = ilow, j = 0; i < ihigh; i++, j++)
378 PyObject* pyobj = list->GetValue(i)->ConvertValueToPython();
380 pyobj = list->GetValue(i)->GetProxy();
381 PyList_SET_ITEM(newlist, i, pyobj);
387 /* clist + list, return a list that python owns */
388 static PyObject *listvalue_buffer_concat(PyObject * self, PyObject * other)
390 CListValue *listval= static_cast<CListValue *>(BGE_PROXY_REF(self));
391 int i, numitems, numitems_orig;
394 PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG);
398 numitems_orig= listval->GetCount();
400 // for now, we support CListValue concatenated with items
401 // and CListValue concatenated to Python Lists
402 // and CListValue concatenated with another CListValue
404 /* Shallow copy, dont use listval->GetReplica(), it will screw up with KX_GameObjects */
405 CListValue* listval_new = new CListValue();
407 if (PyList_Check(other))
412 numitems = PyList_Size(other);
414 /* copy the first part of the list */
415 listval_new->Resize(numitems_orig + numitems);
416 for (i=0;i<numitems_orig;i++)
417 listval_new->SetValue(i, listval->GetValue(i)->AddRef());
419 for (i=0;i<numitems;i++)
421 listitemval = listval->ConvertPythonToValue(PyList_GetItem(other,i), "cList + pyList: CListValue, ");
424 listval_new->SetValue(i+numitems_orig, listitemval);
432 listval_new->Resize(numitems_orig+i); /* resize so we dont try release NULL pointers */
433 listval_new->Release();
434 return NULL; /* ConvertPythonToValue above sets the error */
438 else if (PyObject_TypeCheck(other, &CListValue::Type)) {
439 // add items from otherlist to this list
440 CListValue* otherval = static_cast<CListValue *>(BGE_PROXY_REF(other));
442 listval_new->Release();
443 PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG);
447 numitems = otherval->GetCount();
449 /* copy the first part of the list */
450 listval_new->Resize(numitems_orig + numitems); /* resize so we dont try release NULL pointers */
451 for (i=0;i<numitems_orig;i++)
452 listval_new->SetValue(i, listval->GetValue(i)->AddRef());
454 /* now copy the other part of the list */
455 for (i=0;i<numitems;i++)
456 listval_new->SetValue(i+numitems_orig, otherval->GetValue(i)->AddRef());
459 return listval_new->NewProxy(true); /* python owns this list */
462 static int listvalue_buffer_contains(PyObject *self_v, PyObject *value)
464 CListValue *self= static_cast<CListValue *>(BGE_PROXY_REF(self_v));
467 PyErr_SetString(PyExc_SystemError, "val in CList, "BGE_PROXY_ERROR_MSG);
471 if (PyUnicode_Check(value)) {
472 if (self->FindValue((const char *)_PyUnicode_AsString(value))) {
476 else if (PyObject_TypeCheck(value, &CValue::Type)) { /* not dict like at all but this worked before __contains__ was used */
477 CValue *item= static_cast<CValue *>(BGE_PROXY_REF(value));
478 for (int i=0; i < self->GetCount(); i++)
479 if (self->GetValue(i) == item) // Com
482 } // not using CheckEqual
488 static PySequenceMethods listvalue_as_sequence = {
489 listvalue_bufferlen,//(inquiry)buffer_length, /*sq_length*/
490 listvalue_buffer_concat, /*sq_concat*/
492 listvalue_buffer_item, /*sq_item*/
493 // TODO, slicing in py3
494 NULL, // listvalue_buffer_slice, /*sq_slice*/
495 NULL, /*sq_ass_item*/
496 NULL, /*sq_ass_slice*/
497 (objobjproc)listvalue_buffer_contains, /* sq_contains */
502 /* Is this one used ? */
503 static PyMappingMethods instance_as_mapping = {
504 listvalue_bufferlen, /*mp_length*/
505 listvalue_mapping_subscript, /*mp_subscript*/
506 NULL /*mp_ass_subscript*/
511 PyTypeObject CListValue::Type = {
512 PyVarObject_HEAD_INIT(NULL, 0)
513 "CListValue", /*tp_name*/
514 sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/
517 py_base_dealloc, /*tp_dealloc*/
522 py_base_repr, /*tp_repr*/
524 &listvalue_as_sequence, /*tp_as_sequence*/
525 &instance_as_mapping, /*tp_as_mapping*/
532 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
542 PyMethodDef CListValue::Methods[] = {
543 /* List style access */
544 {"append", (PyCFunction)CListValue::sPyappend,METH_O},
545 {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS},
546 {"index", (PyCFunction)CListValue::sPyindex,METH_O},
547 {"count", (PyCFunction)CListValue::sPycount,METH_O},
549 /* Dict style access */
550 {"get", (PyCFunction)CListValue::sPyget,METH_VARARGS},
552 /* Own cvalue funcs */
553 {"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O},
555 {NULL,NULL} //Sentinel
558 PyAttributeDef CListValue::Attributes[] = {
562 PyObject* CListValue::Pyappend(PyObject* value)
564 CValue* objval = ConvertPythonToValue(value, "CList.append(i): CValueList, ");
566 if (!objval) /* ConvertPythonToValue sets the error */
569 if (!BGE_PROXY_PYOWNS(m_proxy)) {
570 PyErr_SetString(PyExc_TypeError, "CList.append(i): this CValueList is used internally for the game engine and can't be modified");
579 PyObject* CListValue::Pyreverse()
581 std::reverse(m_pValueArray.begin(),m_pValueArray.end());
585 PyObject* CListValue::Pyindex(PyObject *value)
587 PyObject* result = NULL;
589 CValue* checkobj = ConvertPythonToValue(value, "val = cList[i]: CValueList, ");
591 return NULL; /* ConvertPythonToValue sets the error */
593 int numelem = GetCount();
594 for (int i=0;i<numelem;i++)
596 CValue* elem = GetValue(i);
597 if (checkobj==elem || CheckEqual(checkobj,elem))
599 result = PyLong_FromSsize_t(i);
606 PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in CListValue");
614 PyObject* CListValue::Pycount(PyObject* value)
618 CValue* checkobj = ConvertPythonToValue(value, ""); /* error ignored */
620 if (checkobj==NULL) { /* in this case just return that there are no items in the list */
622 return PyLong_FromSsize_t(0);
625 int numelem = GetCount();
626 for (int i=0;i<numelem;i++)
628 CValue* elem = GetValue(i);
629 if (checkobj==elem || CheckEqual(checkobj,elem))
636 return PyLong_FromSsize_t(numfound);
639 /* Matches python dict.get(key, [default]) */
640 PyObject* CListValue::Pyget(PyObject *args)
643 PyObject* def = Py_None;
645 if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
648 CValue *item = FindValue((const char *)key);
650 PyObject* pyobj = item->ConvertValueToPython();
654 return item->GetProxy();
661 PyObject* CListValue::Pyfrom_id(PyObject* value)
663 uintptr_t id= (uintptr_t)PyLong_AsVoidPtr(value);
665 if (PyErr_Occurred())
668 int numelem = GetCount();
669 for (int i=0;i<numelem;i++)
671 if (reinterpret_cast<uintptr_t>(m_pValueArray[i]->m_proxy) == id)
672 return GetValue(i)->GetProxy();
674 PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in CValueList");
679 #endif // DISABLE_PYTHON