diff options
Diffstat (limited to 'source/gameengine/Expressions/intern/ListValue.cpp')
-rw-r--r-- | source/gameengine/Expressions/intern/ListValue.cpp | 702 |
1 files changed, 702 insertions, 0 deletions
diff --git a/source/gameengine/Expressions/intern/ListValue.cpp b/source/gameengine/Expressions/intern/ListValue.cpp new file mode 100644 index 00000000000..557ce7be300 --- /dev/null +++ b/source/gameengine/Expressions/intern/ListValue.cpp @@ -0,0 +1,702 @@ +/** \file gameengine/Expressions/ListValue.cpp + * \ingroup expressions + */ +// ListValue.cpp: implementation of the CListValue class. +// +////////////////////////////////////////////////////////////////////// +/* + * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org> + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Erwin Coumans makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#include <stdio.h> + +#include "EXP_ListValue.h" +#include "EXP_StringValue.h" +#include "EXP_VoidValue.h" +#include <algorithm> +#include "EXP_BoolValue.h" + +#include "BLI_sys_types.h" /* for intptr_t support */ + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CListValue::CListValue() +: CPropValue() +{ + m_bReleaseContents=true; +} + + + +CListValue::~CListValue() +{ + + if (m_bReleaseContents) { + for (unsigned int i=0;i<m_pValueArray.size();i++) { + m_pValueArray[i]->Release(); + } + } +} + + +static STR_String gstrListRep=STR_String("List"); + +const STR_String & CListValue::GetText() +{ + gstrListRep = "["; + STR_String commastr = ""; + + for (int i=0;i<GetCount();i++) + { + gstrListRep += commastr; + gstrListRep += GetValue(i)->GetText(); + commastr = ","; + } + gstrListRep += "]"; + + return gstrListRep; +} + + + +CValue* CListValue::GetReplica() +{ + CListValue* replica = new CListValue(*this); + + replica->ProcessReplica(); + + replica->m_bReleaseContents=true; // for copy, complete array is copied for now... + // copy all values + int numelements = m_pValueArray.size(); + unsigned int i=0; + replica->m_pValueArray.resize(numelements); + for (i=0;i<m_pValueArray.size();i++) + replica->m_pValueArray[i] = m_pValueArray[i]->GetReplica(); + + + return replica; +}; + + + +void CListValue::SetValue(int i, CValue *val) +{ + assertd(i < m_pValueArray.size()); + m_pValueArray[i]=val; +} + + + +void CListValue::Resize(int num) +{ + m_pValueArray.resize(num); +} + + + +void CListValue::Remove(int i) +{ + assertd(i<m_pValueArray.size()); + m_pValueArray.erase(m_pValueArray.begin()+i); +} + + + +void CListValue::ReleaseAndRemoveAll() +{ + for (unsigned int i=0;i<m_pValueArray.size();i++) + m_pValueArray[i]->Release(); + m_pValueArray.clear();//.Clear(); +} + + + +CValue* CListValue::FindValue(const STR_String &name) +{ + for (int i=0; i < GetCount(); i++) + if (GetValue(i)->GetName() == name) + return GetValue(i); + + return NULL; +} + +CValue* CListValue::FindValue(const char *name) +{ + for (int i=0; i < GetCount(); i++) + if (GetValue(i)->GetName() == name) + return GetValue(i); + + return NULL; +} + +bool CListValue::SearchValue(CValue *val) +{ + for (int i=0;i<GetCount();i++) + if (val == GetValue(i)) + return true; + return false; +} + + + +void CListValue::SetReleaseOnDestruct(bool bReleaseContents) +{ + m_bReleaseContents = bReleaseContents; +} + + + +bool CListValue::RemoveValue(CValue *val) +{ + bool result=false; + + for (int i=GetCount()-1;i>=0;i--) + if (val == GetValue(i)) + { + Remove(i); + result=true; + } + return result; +} + + + +void CListValue::MergeList(CListValue *otherlist) +{ + + int numelements = this->GetCount(); + int numotherelements = otherlist->GetCount(); + + + Resize(numelements+numotherelements); + + for (int i=0;i<numotherelements;i++) + { + SetValue(i+numelements,otherlist->GetValue(i)->AddRef()); + } +} + +bool CListValue::CheckEqual(CValue* first,CValue* second) +{ + bool result = false; + + CValue* eqval = ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second); + + if (eqval==NULL) + return false; + const STR_String& text = eqval->GetText(); + if (&text==&CBoolValue::sTrueString) + { + result = true; + } + eqval->Release(); + return result; + +} + + +/* --------------------------------------------------------------------- + * Some stuff taken from the header + * --------------------------------------------------------------------- */ +CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val) +{ + //assert(false); // todo: implement me! + static int error_printed = 0; + if (error_printed==0) { + fprintf(stderr, "CValueList::Calc not yet implemented\n"); + error_printed = 1; + } + return NULL; +} + +CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype, + VALUE_OPERATOR op, + CValue* val) +{ + //assert(false); // todo: implement me! + static int error_printed = 0; + if (error_printed==0) { + fprintf(stderr, "CValueList::CalcFinal not yet implemented\n"); + error_printed = 1; + } + return NULL; +} + + + +void CListValue::Add(CValue* value) +{ + m_pValueArray.push_back(value); +} + + + +double CListValue::GetNumber() +{ + return -1; +} + + + +int CListValue::GetValueType() +{ + return VALUE_LIST_TYPE; +} + + + +void CListValue::SetModified(bool bModified) +{ + CValue::SetModified(bModified); + int numels = GetCount(); + + for (int i=0;i<numels;i++) + GetValue(i)->SetModified(bModified); +} + + + +bool CListValue::IsModified() +{ + bool bmod = CValue::IsModified(); //normal own flag + int numels = GetCount(); + + for (int i=0;i<numels;i++) + bmod = bmod || GetValue(i)->IsModified(); + + return bmod; +} + +#ifdef WITH_PYTHON + +/* --------------------------------------------------------------------- */ +/* Python interface ---------------------------------------------------- */ +/* --------------------------------------------------------------------- */ + +static Py_ssize_t listvalue_bufferlen(PyObject *self) +{ + CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); + if (list==NULL) + return 0; + + return (Py_ssize_t)list->GetCount(); +} + +static PyObject *listvalue_buffer_item(PyObject *self, Py_ssize_t index) +{ + CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); + CValue *cval; + + if (list==NULL) { + PyErr_SetString(PyExc_SystemError, "val = CList[i], " BGE_PROXY_ERROR_MSG); + return NULL; + } + + int count = list->GetCount(); + + if (index < 0) + index = count+index; + + if (index < 0 || index >= count) { + PyErr_SetString(PyExc_IndexError, "CList[i]: Python ListIndex out of range in CValueList"); + return NULL; + } + + cval= list->GetValue(index); + + PyObject *pyobj = cval->ConvertValueToPython(); + if (pyobj) + return pyobj; + else + return cval->GetProxy(); +} + + +/* just slice it into a python list... */ +static PyObject *listvalue_buffer_slice(CListValue *list, Py_ssize_t start, Py_ssize_t stop) +{ + PyObject *newlist; + Py_ssize_t i, j; + + /* caller needs to validate negative index */ +#if 0 + Py_ssize_t len = list->GetCount(); + + if (start > len) start = len; + if (stop > len) stop = len; +#endif + + newlist = PyList_New(stop - start); + if (!newlist) + return NULL; + + for (i = start, j = 0; i < stop; i++, j++) { + PyObject *pyobj = list->GetValue(i)->ConvertValueToPython(); + if (!pyobj) { + pyobj = list->GetValue(i)->GetProxy(); + } + PyList_SET_ITEM(newlist, j, pyobj); + } + return newlist; +} + + +static PyObject *listvalue_mapping_subscript(PyObject *self, PyObject *key) +{ + CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self)); + if (list==NULL) { + PyErr_SetString(PyExc_SystemError, "value = CList[i], " BGE_PROXY_ERROR_MSG); + return NULL; + } + + if (PyUnicode_Check(key)) { + CValue *item = ((CListValue*) list)->FindValue(_PyUnicode_AsString(key)); + if (item) { + PyObject *pyobj = item->ConvertValueToPython(); + if (pyobj) + return pyobj; + else + return item->GetProxy(); + } + } + else if (PyIndex_Check(key)) { + Py_ssize_t index = PyLong_AsSsize_t(key); + return listvalue_buffer_item(self, index); /* wont add a ref */ + } + else if (PySlice_Check(key)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx(key, list->GetCount(), &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (slicelength <= 0) { + return PyList_New(0); + } + else if (step == 1) { + return listvalue_buffer_slice(list, start, stop); + } + else { + PyErr_SetString(PyExc_TypeError, "CList[slice]: slice steps not supported"); + return NULL; + } + } + + PyErr_Format(PyExc_KeyError, + "CList[key]: '%R' key not in list", key); + return NULL; +} + +/* clist + list, return a list that python owns */ +static PyObject *listvalue_buffer_concat(PyObject *self, PyObject *other) +{ + CListValue *listval= static_cast<CListValue *>(BGE_PROXY_REF(self)); + Py_ssize_t i, numitems, numitems_orig; + + if (listval==NULL) { + PyErr_SetString(PyExc_SystemError, "CList+other, " BGE_PROXY_ERROR_MSG); + return NULL; + } + + numitems_orig= listval->GetCount(); + + // for now, we support CListValue concatenated with items + // and CListValue concatenated to Python Lists + // and CListValue concatenated with another CListValue + + /* Shallow copy, don't use listval->GetReplica(), it will screw up with KX_GameObjects */ + CListValue* listval_new = new CListValue(); + + if (PyList_Check(other)) + { + CValue* listitemval; + bool error = false; + + numitems = PyList_GET_SIZE(other); + + /* copy the first part of the list */ + listval_new->Resize(numitems_orig + numitems); + for (i=0;i<numitems_orig;i++) + listval_new->SetValue(i, listval->GetValue(i)->AddRef()); + + for (i=0;i<numitems;i++) + { + listitemval = listval->ConvertPythonToValue(PyList_GET_ITEM(other, i), true, "cList + pyList: CListValue, "); + + if (listitemval) { + listval_new->SetValue(i+numitems_orig, listitemval); + } else { + error= true; + break; + } + } + + if (error) { + listval_new->Resize(numitems_orig+i); /* resize so we don't try release NULL pointers */ + listval_new->Release(); + return NULL; /* ConvertPythonToValue above sets the error */ + } + + } + else if (PyObject_TypeCheck(other, &CListValue::Type)) { + // add items from otherlist to this list + CListValue* otherval = static_cast<CListValue *>(BGE_PROXY_REF(other)); + if (otherval==NULL) { + listval_new->Release(); + PyErr_SetString(PyExc_SystemError, "CList+other, " BGE_PROXY_ERROR_MSG); + return NULL; + } + + numitems = otherval->GetCount(); + + /* copy the first part of the list */ + listval_new->Resize(numitems_orig + numitems); /* resize so we don't try release NULL pointers */ + for (i=0;i<numitems_orig;i++) + listval_new->SetValue(i, listval->GetValue(i)->AddRef()); + + /* now copy the other part of the list */ + for (i=0;i<numitems;i++) + listval_new->SetValue(i+numitems_orig, otherval->GetValue(i)->AddRef()); + + } + return listval_new->NewProxy(true); /* python owns this list */ +} + +static int listvalue_buffer_contains(PyObject *self_v, PyObject *value) +{ + CListValue *self = static_cast<CListValue *>(BGE_PROXY_REF(self_v)); + + if (self == NULL) { + PyErr_SetString(PyExc_SystemError, "val in CList, " BGE_PROXY_ERROR_MSG); + return -1; + } + + if (PyUnicode_Check(value)) { + if (self->FindValue((const char *)_PyUnicode_AsString(value))) { + return 1; + } + } + else if (PyObject_TypeCheck(value, &CValue::Type)) { /* not dict like at all but this worked before __contains__ was used */ + CValue *item= static_cast<CValue *>(BGE_PROXY_REF(value)); + for (int i=0; i < self->GetCount(); i++) + if (self->GetValue(i) == item) // Com + return 1; + + } // not using CheckEqual + + return 0; +} + + +static PySequenceMethods listvalue_as_sequence = { + listvalue_bufferlen,//(inquiry)buffer_length, /*sq_length*/ + listvalue_buffer_concat, /*sq_concat*/ + NULL, /*sq_repeat*/ + listvalue_buffer_item, /*sq_item*/ +// TODO, slicing in py3 + NULL, // listvalue_buffer_slice, /*sq_slice*/ + NULL, /*sq_ass_item*/ + NULL, /*sq_ass_slice*/ + (objobjproc)listvalue_buffer_contains, /* sq_contains */ + (binaryfunc) NULL, /* sq_inplace_concat */ + (ssizeargfunc) NULL, /* sq_inplace_repeat */ +}; + + + +/* Is this one used ? */ +static PyMappingMethods instance_as_mapping = { + listvalue_bufferlen, /*mp_length*/ + listvalue_mapping_subscript, /*mp_subscript*/ + NULL /*mp_ass_subscript*/ +}; + + + +PyTypeObject CListValue::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "CListValue", /*tp_name*/ + sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + py_base_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + py_base_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + &listvalue_as_sequence, /*tp_as_sequence*/ + &instance_as_mapping, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call */ + 0, + NULL, + NULL, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &CValue::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyMethodDef CListValue::Methods[] = { + /* List style access */ + {"append", (PyCFunction)CListValue::sPyappend,METH_O}, + {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS}, + {"index", (PyCFunction)CListValue::sPyindex,METH_O}, + {"count", (PyCFunction)CListValue::sPycount,METH_O}, + + /* Dict style access */ + {"get", (PyCFunction)CListValue::sPyget,METH_VARARGS}, + + /* Own cvalue funcs */ + {"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O}, + + {NULL,NULL} //Sentinel +}; + +PyAttributeDef CListValue::Attributes[] = { + { NULL } //Sentinel +}; + +PyObject *CListValue::Pyappend(PyObject *value) +{ + CValue *objval = ConvertPythonToValue(value, true, "CList.append(i): CValueList, "); + + if (!objval) /* ConvertPythonToValue sets the error */ + return NULL; + + if (!BGE_PROXY_PYOWNS(m_proxy)) { + PyErr_SetString(PyExc_TypeError, + "CList.append(i): internal values can't be modified"); + return NULL; + } + + Add(objval); + + Py_RETURN_NONE; +} + +PyObject *CListValue::Pyreverse() +{ + if (!BGE_PROXY_PYOWNS(m_proxy)) { + PyErr_SetString(PyExc_TypeError, + "CList.reverse(): internal values can't be modified"); + return NULL; + } + + std::reverse(m_pValueArray.begin(),m_pValueArray.end()); + Py_RETURN_NONE; +} + +PyObject *CListValue::Pyindex(PyObject *value) +{ + PyObject *result = NULL; + + CValue *checkobj = ConvertPythonToValue(value, true, "val = cList[i]: CValueList, "); + if (checkobj==NULL) + return NULL; /* ConvertPythonToValue sets the error */ + + int numelem = GetCount(); + for (int i=0;i<numelem;i++) + { + CValue* elem = GetValue(i); + if (checkobj==elem || CheckEqual(checkobj,elem)) + { + result = PyLong_FromLong(i); + break; + } + } + checkobj->Release(); + + if (result==NULL) { + PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in CListValue"); + } + return result; + +} + + + +PyObject *CListValue::Pycount(PyObject *value) +{ + int numfound = 0; + + CValue *checkobj = ConvertPythonToValue(value, false, ""); /* error ignored */ + + if (checkobj==NULL) { /* in this case just return that there are no items in the list */ + PyErr_Clear(); + return PyLong_FromLong(0); + } + + int numelem = GetCount(); + for (int i=0;i<numelem;i++) + { + CValue* elem = GetValue(i); + if (checkobj==elem || CheckEqual(checkobj,elem)) + { + numfound ++; + } + } + checkobj->Release(); + + return PyLong_FromLong(numfound); +} + +/* Matches python dict.get(key, [default]) */ +PyObject *CListValue::Pyget(PyObject *args) +{ + char *key; + PyObject *def = Py_None; + + if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) + return NULL; + + CValue *item = FindValue((const char *)key); + if (item) { + PyObject *pyobj = item->ConvertValueToPython(); + if (pyobj) + return pyobj; + else + return item->GetProxy(); + } + Py_INCREF(def); + return def; +} + + +PyObject *CListValue::Pyfrom_id(PyObject *value) +{ + uintptr_t id= (uintptr_t)PyLong_AsVoidPtr(value); + + if (PyErr_Occurred()) + return NULL; + + int numelem = GetCount(); + for (int i=0;i<numelem;i++) + { + if (reinterpret_cast<uintptr_t>(m_pValueArray[i]->m_proxy) == id) + return GetValue(i)->GetProxy(); + } + PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in CValueList"); + return NULL; + +} + +#endif // WITH_PYTHON |