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.
17 #include "ListValue.h"
18 #include "StringValue.h"
19 #include "VoidValue.h"
21 #include "BoolValue.h"
23 #include "BLO_sys_types.h" /* for intptr_t support */
29 #if ((PY_MAJOR_VERSION == 2) &&(PY_MINOR_VERSION < 5))
30 #define Py_ssize_t int
33 Py_ssize_t listvalue_bufferlen(PyObject* self)
35 CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
39 return (Py_ssize_t)list->GetCount();
42 PyObject* listvalue_buffer_item(PyObject* self, Py_ssize_t index)
44 CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
48 PyErr_SetString(PyExc_SystemError, "val = CList[i], "BGE_PROXY_ERROR_MSG);
52 int count = list->GetCount();
57 if (index < 0 || index >= count) {
58 PyErr_SetString(PyExc_IndexError, "CList[i]: Python ListIndex out of range in CValueList");
62 cval= list->GetValue(index);
64 PyObject* pyobj = cval->ConvertValueToPython();
68 return cval->GetProxy();
71 PyObject* listvalue_mapping_subscript(PyObject* self, PyObject* pyindex)
73 CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
75 PyErr_SetString(PyExc_SystemError, "value = CList[i], "BGE_PROXY_ERROR_MSG);
79 if (PyUnicode_Check(pyindex))
81 CValue *item = ((CListValue*) list)->FindValue(_PyUnicode_AsString(pyindex));
83 PyObject* pyobj = item->ConvertValueToPython();
87 return item->GetProxy();
90 else if (PyLong_Check(pyindex))
92 int index = PyLong_AsSsize_t(pyindex);
93 return listvalue_buffer_item(self, index); /* wont add a ref */
96 PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */
97 PyErr_Format(PyExc_KeyError, "CList[key]: '%s' key not in list", _PyUnicode_AsString(pyindex_str));
98 Py_DECREF(pyindex_str);
103 /* just slice it into a python list... */
104 PyObject* listvalue_buffer_slice(PyObject* self,Py_ssize_t ilow, Py_ssize_t ihigh)
106 CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
108 PyErr_SetString(PyExc_SystemError, "val = CList[i:j], "BGE_PROXY_ERROR_MSG);
115 if (ilow < 0) ilow = 0;
117 int n = ((CListValue*) list)->GetCount();
124 newlist = PyList_New(ihigh - ilow);
128 for (i = ilow, j = 0; i < ihigh; i++, j++)
130 PyObject* pyobj = list->GetValue(i)->ConvertValueToPython();
132 pyobj = list->GetValue(i)->GetProxy();
133 PyList_SET_ITEM(newlist, i, pyobj);
139 /* clist + list, return a list that python owns */
140 static PyObject *listvalue_buffer_concat(PyObject * self, PyObject * other)
142 CListValue *listval= static_cast<CListValue *>(BGE_PROXY_REF(self));
143 int i, numitems, numitems_orig;
146 PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG);
150 numitems_orig= listval->GetCount();
152 // for now, we support CListValue concatenated with items
153 // and CListValue concatenated to Python Lists
154 // and CListValue concatenated with another CListValue
156 /* Shallow copy, dont use listval->GetReplica(), it will screw up with KX_GameObjects */
157 CListValue* listval_new = new CListValue();
159 if (PyList_Check(other))
164 numitems = PyList_Size(other);
166 /* copy the first part of the list */
167 listval_new->Resize(numitems_orig + numitems);
168 for (i=0;i<numitems_orig;i++)
169 listval_new->SetValue(i, listval->GetValue(i)->AddRef());
171 for (i=0;i<numitems;i++)
173 listitemval = listval->ConvertPythonToValue(PyList_GetItem(other,i), "cList + pyList: CListValue, ");
176 listval_new->SetValue(i+numitems_orig, listitemval);
184 listval_new->Resize(numitems_orig+i); /* resize so we dont try release NULL pointers */
185 listval_new->Release();
186 return NULL; /* ConvertPythonToValue above sets the error */
190 else if (PyObject_TypeCheck(other, &CListValue::Type)) {
191 // add items from otherlist to this list
192 CListValue* otherval = static_cast<CListValue *>(BGE_PROXY_REF(other));
194 listval_new->Release();
195 PyErr_SetString(PyExc_SystemError, "CList+other, "BGE_PROXY_ERROR_MSG);
199 numitems = otherval->GetCount();
201 /* copy the first part of the list */
202 listval_new->Resize(numitems_orig + numitems); /* resize so we dont try release NULL pointers */
203 for (i=0;i<numitems_orig;i++)
204 listval_new->SetValue(i, listval->GetValue(i)->AddRef());
206 /* now copy the other part of the list */
207 for (i=0;i<numitems;i++)
208 listval_new->SetValue(i+numitems_orig, otherval->GetValue(i)->AddRef());
211 return listval_new->NewProxy(true); /* python owns this list */
214 static int listvalue_buffer_contains(PyObject *self_v, PyObject *value)
216 CListValue *self= static_cast<CListValue *>(BGE_PROXY_REF(self_v));
219 PyErr_SetString(PyExc_SystemError, "val in CList, "BGE_PROXY_ERROR_MSG);
223 if (PyUnicode_Check(value)) {
224 if (self->FindValue((const char *)_PyUnicode_AsString(value))) {
228 else if (PyObject_TypeCheck(value, &CValue::Type)) { /* not dict like at all but this worked before __contains__ was used */
229 CValue *item= static_cast<CValue *>(BGE_PROXY_REF(value));
230 for (int i=0; i < self->GetCount(); i++)
231 if (self->GetValue(i) == item) // Com
234 } // not using CheckEqual
240 static PySequenceMethods listvalue_as_sequence = {
241 listvalue_bufferlen,//(inquiry)buffer_length, /*sq_length*/
242 listvalue_buffer_concat, /*sq_concat*/
244 listvalue_buffer_item, /*sq_item*/
245 // TODO, slicing in py3
246 NULL, // listvalue_buffer_slice, /*sq_slice*/
247 NULL, /*sq_ass_item*/
248 NULL, /*sq_ass_slice*/
249 (objobjproc)listvalue_buffer_contains, /* sq_contains */
254 /* Is this one used ? */
255 static PyMappingMethods instance_as_mapping = {
256 listvalue_bufferlen, /*mp_length*/
257 listvalue_mapping_subscript, /*mp_subscript*/
258 NULL /*mp_ass_subscript*/
263 PyTypeObject CListValue::Type = {
264 PyVarObject_HEAD_INIT(NULL, 0)
265 "CListValue", /*tp_name*/
266 sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/
269 py_base_dealloc, /*tp_dealloc*/
274 py_base_repr, /*tp_repr*/
276 &listvalue_as_sequence, /*tp_as_sequence*/
277 &instance_as_mapping, /*tp_as_mapping*/
284 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
294 PyMethodDef CListValue::Methods[] = {
295 /* List style access */
296 {"append", (PyCFunction)CListValue::sPyappend,METH_O},
297 {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS},
298 {"index", (PyCFunction)CListValue::sPyindex,METH_O},
299 {"count", (PyCFunction)CListValue::sPycount,METH_O},
301 /* Dict style access */
302 {"get", (PyCFunction)CListValue::sPyget,METH_VARARGS},
304 /* Own cvalue funcs */
305 {"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O},
307 {NULL,NULL} //Sentinel
310 PyAttributeDef CListValue::Attributes[] = {
314 //////////////////////////////////////////////////////////////////////
315 // Construction/Destruction
316 //////////////////////////////////////////////////////////////////////
318 CListValue::CListValue()
321 m_bReleaseContents=true;
326 CListValue::~CListValue()
329 if (m_bReleaseContents) {
330 for (unsigned int i=0;i<m_pValueArray.size();i++) {
331 m_pValueArray[i]->Release();
337 static STR_String gstrListRep=STR_String("List");
339 const STR_String & CListValue::GetText()
342 STR_String commastr = "";
344 for (int i=0;i<GetCount();i++)
346 gstrListRep += commastr;
347 gstrListRep += GetValue(i)->GetText();
357 CValue* CListValue::GetReplica() {
358 CListValue* replica = new CListValue(*this);
360 replica->ProcessReplica();
362 replica->m_bReleaseContents=true; // for copy, complete array is copied for now...
364 int numelements = m_pValueArray.size();
366 replica->m_pValueArray.resize(numelements);
367 for (i=0;i<m_pValueArray.size();i++)
368 replica->m_pValueArray[i] = m_pValueArray[i]->GetReplica();
376 void CListValue::SetValue(int i, CValue *val)
378 assertd(i < m_pValueArray.size());
379 m_pValueArray[i]=val;
384 void CListValue::Resize(int num)
386 m_pValueArray.resize(num);
391 void CListValue::Remove(int i)
393 assertd(i<m_pValueArray.size());
394 m_pValueArray.erase(m_pValueArray.begin()+i);
399 void CListValue::ReleaseAndRemoveAll()
401 for (unsigned int i=0;i<m_pValueArray.size();i++)
402 m_pValueArray[i]->Release();
403 m_pValueArray.clear();//.Clear();
408 CValue* CListValue::FindValue(const STR_String & name)
410 for (int i=0; i < GetCount(); i++)
411 if (GetValue(i)->GetName() == name)
417 CValue* CListValue::FindValue(const char * name)
419 for (int i=0; i < GetCount(); i++)
420 if (GetValue(i)->GetName() == name)
426 bool CListValue::SearchValue(CValue *val)
428 for (int i=0;i<GetCount();i++)
429 if (val == GetValue(i))
436 void CListValue::SetReleaseOnDestruct(bool bReleaseContents)
438 m_bReleaseContents = bReleaseContents;
443 bool CListValue::RemoveValue(CValue *val)
447 for (int i=GetCount()-1;i>=0;i--)
448 if (val == GetValue(i))
458 void CListValue::MergeList(CListValue *otherlist)
461 int numelements = this->GetCount();
462 int numotherelements = otherlist->GetCount();
465 Resize(numelements+numotherelements);
467 for (int i=0;i<numotherelements;i++)
469 SetValue(i+numelements,otherlist->GetValue(i)->AddRef());
474 PyObject* CListValue::Pyappend(PyObject* value)
476 CValue* objval = ConvertPythonToValue(value, "CList.append(i): CValueList, ");
478 if (!objval) /* ConvertPythonToValue sets the error */
481 if (!BGE_PROXY_PYOWNS(m_proxy)) {
482 PyErr_SetString(PyExc_TypeError, "CList.append(i): this CValueList is used internally for the game engine and can't be modified");
493 PyObject* CListValue::Pyreverse()
495 std::reverse(m_pValueArray.begin(),m_pValueArray.end());
501 bool CListValue::CheckEqual(CValue* first,CValue* second)
505 CValue* eqval = ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second);
509 const STR_String& text = eqval->GetText();
510 if (&text==&CBoolValue::sTrueString)
521 PyObject* CListValue::Pyindex(PyObject *value)
523 PyObject* result = NULL;
525 CValue* checkobj = ConvertPythonToValue(value, "val = cList[i]: CValueList, ");
527 return NULL; /* ConvertPythonToValue sets the error */
529 int numelem = GetCount();
530 for (int i=0;i<numelem;i++)
532 CValue* elem = GetValue(i);
533 if (checkobj==elem || CheckEqual(checkobj,elem))
535 result = PyLong_FromSsize_t(i);
542 PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in CListValue");
550 PyObject* CListValue::Pycount(PyObject* value)
554 CValue* checkobj = ConvertPythonToValue(value, ""); /* error ignored */
556 if (checkobj==NULL) { /* in this case just return that there are no items in the list */
558 return PyLong_FromSsize_t(0);
561 int numelem = GetCount();
562 for (int i=0;i<numelem;i++)
564 CValue* elem = GetValue(i);
565 if (checkobj==elem || CheckEqual(checkobj,elem))
572 return PyLong_FromSsize_t(numfound);
575 /* Matches python dict.get(key, [default]) */
576 PyObject* CListValue::Pyget(PyObject *args)
579 PyObject* def = Py_None;
581 if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
584 CValue *item = FindValue((const char *)key);
586 PyObject* pyobj = item->ConvertValueToPython();
590 return item->GetProxy();
597 PyObject* CListValue::Pyfrom_id(PyObject* value)
599 uintptr_t id= (uintptr_t)PyLong_AsVoidPtr(value);
601 if (PyErr_Occurred())
604 int numelem = GetCount();
605 for (int i=0;i<numelem;i++)
607 if (reinterpret_cast<uintptr_t>(m_pValueArray[i]->m_proxy) == id)
608 return GetValue(i)->GetProxy();
610 PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in CValueList");
616 /* ---------------------------------------------------------------------
617 * Some stuff taken from the header
618 * --------------------------------------------------------------------- */
619 CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val)
621 //assert(false); // todo: implement me!
622 static int error_printed = 0;
623 if (error_printed==0) {
624 fprintf(stderr, "CValueList::Calc not yet implimented\n");
630 CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype,
634 //assert(false); // todo: implement me!
635 static int error_printed = 0;
636 if (error_printed==0) {
637 fprintf(stderr, "CValueList::CalcFinal not yet implimented\n");
645 void CListValue::Add(CValue* value)
647 m_pValueArray.push_back(value);
652 double CListValue::GetNumber()
659 void CListValue::SetModified(bool bModified)
661 CValue::SetModified(bModified);
662 int numels = GetCount();
664 for (int i=0;i<numels;i++)
665 GetValue(i)->SetModified(bModified);
670 bool CListValue::IsModified()
672 bool bmod = CValue::IsModified(); //normal own flag
673 int numels = GetCount();
675 for (int i=0;i<numels;i++)
676 bmod = bmod || GetValue(i)->IsModified();