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 #if (PY_VERSION_HEX >= 0x03000000) // TODO, slicing in py3?
250 listvalue_buffer_slice, /*sq_slice*/
251 NULL, /*sq_ass_item*/
252 NULL, /*sq_ass_slice*/
254 (objobjproc)listvalue_buffer_contains, /* sq_contains */
259 /* Is this one used ? */
260 static PyMappingMethods instance_as_mapping = {
261 listvalue_bufferlen, /*mp_length*/
262 listvalue_mapping_subscript, /*mp_subscript*/
263 NULL /*mp_ass_subscript*/
268 PyTypeObject CListValue::Type = {
269 #if (PY_VERSION_HEX >= 0x02060000)
270 PyVarObject_HEAD_INIT(NULL, 0)
272 /* python 2.5 and below */
273 PyObject_HEAD_INIT( NULL ) /* required py macro */
276 "CListValue", /*tp_name*/
277 sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/
280 py_base_dealloc, /*tp_dealloc*/
285 py_base_repr, /*tp_repr*/
287 &listvalue_as_sequence, /*tp_as_sequence*/
288 &instance_as_mapping, /*tp_as_mapping*/
295 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
305 PyMethodDef CListValue::Methods[] = {
306 /* List style access */
307 {"append", (PyCFunction)CListValue::sPyappend,METH_O},
308 {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS},
309 {"index", (PyCFunction)CListValue::sPyindex,METH_O},
310 {"count", (PyCFunction)CListValue::sPycount,METH_O},
312 /* Dict style access */
313 {"get", (PyCFunction)CListValue::sPyget,METH_VARARGS},
314 {"has_key", (PyCFunction)CListValue::sPyhas_key,METH_O},
316 /* Own cvalue funcs */
317 {"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O},
319 {NULL,NULL} //Sentinel
322 PyAttributeDef CListValue::Attributes[] = {
326 //////////////////////////////////////////////////////////////////////
327 // Construction/Destruction
328 //////////////////////////////////////////////////////////////////////
330 CListValue::CListValue()
333 m_bReleaseContents=true;
338 CListValue::~CListValue()
341 if (m_bReleaseContents) {
342 for (unsigned int i=0;i<m_pValueArray.size();i++) {
343 m_pValueArray[i]->Release();
349 static STR_String gstrListRep=STR_String("List");
351 const STR_String & CListValue::GetText()
354 STR_String commastr = "";
356 for (int i=0;i<GetCount();i++)
358 gstrListRep += commastr;
359 gstrListRep += GetValue(i)->GetText();
369 CValue* CListValue::GetReplica() {
370 CListValue* replica = new CListValue(*this);
372 replica->ProcessReplica();
374 replica->m_bReleaseContents=true; // for copy, complete array is copied for now...
376 int numelements = m_pValueArray.size();
378 replica->m_pValueArray.resize(numelements);
379 for (i=0;i<m_pValueArray.size();i++)
380 replica->m_pValueArray[i] = m_pValueArray[i]->GetReplica();
388 void CListValue::SetValue(int i, CValue *val)
390 assertd(i < m_pValueArray.size());
391 m_pValueArray[i]=val;
396 void CListValue::Resize(int num)
398 m_pValueArray.resize(num);
403 void CListValue::Remove(int i)
405 assertd(i<m_pValueArray.size());
406 m_pValueArray.erase(m_pValueArray.begin()+i);
411 void CListValue::ReleaseAndRemoveAll()
413 for (unsigned int i=0;i<m_pValueArray.size();i++)
414 m_pValueArray[i]->Release();
415 m_pValueArray.clear();//.Clear();
420 CValue* CListValue::FindValue(const STR_String & name)
422 for (int i=0; i < GetCount(); i++)
423 if (GetValue(i)->GetName() == name)
429 CValue* CListValue::FindValue(const char * name)
431 for (int i=0; i < GetCount(); i++)
432 if (GetValue(i)->GetName() == name)
438 bool CListValue::SearchValue(CValue *val)
440 for (int i=0;i<GetCount();i++)
441 if (val == GetValue(i))
448 void CListValue::SetReleaseOnDestruct(bool bReleaseContents)
450 m_bReleaseContents = bReleaseContents;
455 bool CListValue::RemoveValue(CValue *val)
459 for (int i=GetCount()-1;i>=0;i--)
460 if (val == GetValue(i))
470 void CListValue::MergeList(CListValue *otherlist)
473 int numelements = this->GetCount();
474 int numotherelements = otherlist->GetCount();
477 Resize(numelements+numotherelements);
479 for (int i=0;i<numotherelements;i++)
481 SetValue(i+numelements,otherlist->GetValue(i)->AddRef());
486 PyObject* CListValue::Pyappend(PyObject* value)
488 CValue* objval = ConvertPythonToValue(value, "CList.append(i): CValueList, ");
490 if (!objval) /* ConvertPythonToValue sets the error */
493 if (!BGE_PROXY_PYOWNS(m_proxy)) {
494 PyErr_SetString(PyExc_TypeError, "CList.append(i): this CValueList is used internally for the game engine and can't be modified");
505 PyObject* CListValue::Pyreverse()
507 std::reverse(m_pValueArray.begin(),m_pValueArray.end());
513 bool CListValue::CheckEqual(CValue* first,CValue* second)
517 CValue* eqval = ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second);
521 const STR_String& text = eqval->GetText();
522 if (&text==&CBoolValue::sTrueString)
533 PyObject* CListValue::Pyindex(PyObject *value)
535 PyObject* result = NULL;
537 CValue* checkobj = ConvertPythonToValue(value, "val = cList[i]: CValueList, ");
539 return NULL; /* ConvertPythonToValue sets the error */
541 int numelem = GetCount();
542 for (int i=0;i<numelem;i++)
544 CValue* elem = GetValue(i);
545 if (checkobj==elem || CheckEqual(checkobj,elem))
547 result = PyLong_FromSsize_t(i);
554 PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in CListValue");
562 PyObject* CListValue::Pycount(PyObject* value)
566 CValue* checkobj = ConvertPythonToValue(value, ""); /* error ignored */
568 if (checkobj==NULL) { /* in this case just return that there are no items in the list */
570 return PyLong_FromSsize_t(0);
573 int numelem = GetCount();
574 for (int i=0;i<numelem;i++)
576 CValue* elem = GetValue(i);
577 if (checkobj==elem || CheckEqual(checkobj,elem))
584 return PyLong_FromSsize_t(numfound);
587 /* Matches python dict.get(key, [default]) */
588 PyObject* CListValue::Pyget(PyObject *args)
591 PyObject* def = Py_None;
593 if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
596 CValue *item = FindValue((const char *)key);
598 PyObject* pyobj = item->ConvertValueToPython();
602 return item->GetProxy();
608 /* Matches python dict.has_key() */
609 PyObject* CListValue::Pyhas_key(PyObject* value)
611 if (PyUnicode_Check(value) && FindValue((const char *)_PyUnicode_AsString(value)))
617 PyObject* CListValue::Pyfrom_id(PyObject* value)
619 uintptr_t id= (uintptr_t)PyLong_AsVoidPtr(value);
621 if (PyErr_Occurred())
624 int numelem = GetCount();
625 for (int i=0;i<numelem;i++)
627 if (reinterpret_cast<uintptr_t>(m_pValueArray[i]->m_proxy) == id)
628 return GetValue(i)->GetProxy();
630 PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in CValueList");
636 /* ---------------------------------------------------------------------
637 * Some stuff taken from the header
638 * --------------------------------------------------------------------- */
639 CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val)
641 //assert(false); // todo: implement me!
642 static int error_printed = 0;
643 if (error_printed==0) {
644 fprintf(stderr, "CValueList::Calc not yet implimented\n");
650 CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype,
654 //assert(false); // todo: implement me!
655 static int error_printed = 0;
656 if (error_printed==0) {
657 fprintf(stderr, "CValueList::CalcFinal not yet implimented\n");
665 void CListValue::Add(CValue* value)
667 m_pValueArray.push_back(value);
672 double CListValue::GetNumber()
679 void CListValue::SetModified(bool bModified)
681 CValue::SetModified(bModified);
682 int numels = GetCount();
684 for (int i=0;i<numels;i++)
685 GetValue(i)->SetModified(bModified);
690 bool CListValue::IsModified()
692 bool bmod = CValue::IsModified(); //normal own flag
693 int numels = GetCount();
695 for (int i=0;i<numels;i++)
696 bmod = bmod || GetValue(i)->IsModified();