blender/source/gameengine/Expressions/ListValue.cpp

610 lines
12 KiB
C++
Raw Normal View History

2002-10-12 11:37:38 +00:00
// 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 "ListValue.h"
#include "StringValue.h"
#include "VoidValue.h"
#include <algorithm>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if ((PY_MAJOR_VERSION == 2) &&(PY_MINOR_VERSION < 5))
#define Py_ssize_t int
#endif
Py_ssize_t listvalue_bufferlen(PyObject* self)
2002-10-12 11:37:38 +00:00
{
CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
if (list==NULL)
return 0;
return (Py_ssize_t)list->GetCount();
2002-10-12 11:37:38 +00:00
}
PyObject* listvalue_buffer_item(PyObject* self, Py_ssize_t index)
2002-10-12 11:37:38 +00:00
{
CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
if (list==NULL) {
PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG);
return NULL;
}
int count = list->GetCount();
if (index < 0)
index = count+index;
if (index >= 0 && index < count)
2002-10-12 11:37:38 +00:00
{
PyObject* pyobj = list->GetValue(index)->ConvertValueToPython();
2002-10-12 11:37:38 +00:00
if (pyobj)
return pyobj;
else
return list->GetValue(index)->GetProxy();
2002-10-12 11:37:38 +00:00
}
PyErr_SetString(PyExc_IndexError, "list[i]: Python ListIndex out of range in CValueList");
2002-10-12 11:37:38 +00:00
return NULL;
}
PyObject* listvalue_mapping_subscript(PyObject* self, PyObject* pyindex)
{
CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
if (list==NULL) {
PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG);
return NULL;
}
if (PyString_Check(pyindex))
{
STR_String index(PyString_AsString(pyindex));
CValue *item = ((CListValue*) list)->FindValue(index);
if (item)
return item->GetProxy();
}
2004-06-07 11:03:12 +00:00
if (PyInt_Check(pyindex))
{
int index = PyInt_AsLong(pyindex);
return listvalue_buffer_item(self, index);
2004-06-07 11:03:12 +00:00
}
PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */
PyErr_Format(PyExc_KeyError, "list[key]: '%s' key not in list", PyString_AsString(pyindex_str));
2004-06-07 11:03:12 +00:00
Py_DECREF(pyindex_str);
return NULL;
}
2002-10-12 11:37:38 +00:00
/* just slice it into a python list... */
PyObject* listvalue_buffer_slice(PyObject* self,Py_ssize_t ilow, Py_ssize_t ihigh)
2002-10-12 11:37:38 +00:00
{
CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
if (list==NULL) {
PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG);
return NULL;
}
2002-10-12 11:37:38 +00:00
int i, j;
PyObject *newlist;
2002-10-12 11:37:38 +00:00
if (ilow < 0) ilow = 0;
int n = ((CListValue*) list)->GetCount();
if (ihigh >= n)
ihigh = n;
if (ihigh < ilow)
ihigh = ilow;
newlist = PyList_New(ihigh - ilow);
2002-10-12 11:37:38 +00:00
if (!newlist)
return NULL;
for (i = ilow, j = 0; i < ihigh; i++, j++)
{
PyObject* pyobj = list->GetValue(i)->ConvertValueToPython();
2002-10-12 11:37:38 +00:00
if (!pyobj)
pyobj = list->GetValue(i)->GetProxy();
PyList_SET_ITEM(newlist, i, pyobj);
2002-10-12 11:37:38 +00:00
}
return newlist;
2002-10-12 11:37:38 +00:00
}
static PyObject *
listvalue_buffer_concat(PyObject * self, PyObject * other)
{
CListValue *listval= static_cast<CListValue *>(BGE_PROXY_REF(self));
if (listval==NULL) {
PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG);
return NULL;
}
2002-10-12 11:37:38 +00:00
// for now, we support CListValue concatenated with items
// and CListValue concatenated to Python Lists
// and CListValue concatenated with another CListValue
2002-10-12 11:37:38 +00:00
listval->AddRef();
if (other->ob_type == &PyList_Type)
{
bool error = false;
int i;
int numitems = PyList_Size(other);
for (i=0;i<numitems;i++)
{
PyObject* listitem = PyList_GetItem(other,i);
CValue* listitemval = listval->ConvertPythonToValue(listitem);
if (listitemval)
{
listval->Add(listitemval);
} else
{
error = true;
}
}
if (error) {
PyErr_SetString(PyExc_SystemError, "list.append(val): couldn't add one or more items to this CValueList");
return NULL;
}
2002-10-12 11:37:38 +00:00
} else
{
if (other->ob_type == &CListValue::Type)
{
// add items from otherlist to this list
CListValue* otherval = (CListValue*) other;
for (int i=0;i<otherval->GetCount();i++)
{
otherval->Add(listval->GetValue(i)->AddRef());
}
}
else
{
CValue* objval = listval->ConvertPythonToValue(other);
if (objval)
{
listval->Add(objval);
} else
{
PyErr_SetString(PyExc_SystemError, "list.append(i): couldn't add item to this CValueList");
return NULL;
2002-10-12 11:37:38 +00:00
}
}
}
return self;
}
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*/
listvalue_buffer_slice, /*sq_slice*/
NULL, /*sq_ass_item*/
NULL /*sq_ass_slice*/
2002-10-12 11:37:38 +00:00
};
/* Is this one used ? */
static PyMappingMethods instance_as_mapping = {
listvalue_bufferlen, /*mp_length*/
listvalue_mapping_subscript, /*mp_subscript*/
NULL /*mp_ass_subscript*/
2002-10-12 11:37:38 +00:00
};
PyTypeObject CListValue::Type = {
PyObject_HEAD_INIT(NULL)
2002-10-12 11:37:38 +00:00
0, /*ob_size*/
"CListValue", /*tp_name*/
sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/
2002-10-12 11:37:38 +00:00
0, /*tp_itemsize*/
/* methods */
py_base_dealloc, /*tp_dealloc*/
2002-10-12 11:37:38 +00:00
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
2002-10-12 11:37:38 +00:00
0, /*tp_compare*/
py_base_repr, /*tp_repr*/
2002-10-12 11:37:38 +00:00
0, /*tp_as_number*/
&listvalue_as_sequence, /*tp_as_sequence*/
2004-06-07 11:03:12 +00:00
&instance_as_mapping, /*tp_as_mapping*/
2002-10-12 11:37:38 +00:00
0, /*tp_hash*/
0, /*tp_call */
0,
py_base_getattro,
py_base_setattro,
0,0,0,0,0,0,0,0,0,
Methods
2002-10-12 11:37:38 +00:00
};
PyParentObject CListValue::Parents[] = {
&CListValue::Type,
&CValue::Type,
NULL
};
PyMethodDef CListValue::Methods[] = {
{"append", (PyCFunction)CListValue::sPyappend,METH_O},
{"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS},
{"index", (PyCFunction)CListValue::sPyindex,METH_O},
{"count", (PyCFunction)CListValue::sPycount,METH_O},
{"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O},
2002-10-12 11:37:38 +00:00
{NULL,NULL} //Sentinel
};
PyAttributeDef CListValue::Attributes[] = {
{ NULL } //Sentinel
};
2002-10-12 11:37:38 +00:00
PyObject* CListValue::py_getattro(PyObject* attr) {
py_getattro_up(CValue);
2002-10-12 11:37:38 +00:00
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CListValue::CListValue(PyTypeObject *T )
: CPropValue(T)
{
m_bReleaseContents=true;
}
CListValue::~CListValue()
{
if (m_bReleaseContents) {
for (unsigned int i=0;i<m_pValueArray.size();i++) {
2002-10-12 11:37:38 +00:00
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);
CValue::AddDataToReplica(replica);
replica->m_bReleaseContents=true; // for copy, complete array is copied for now...
// copy all values
int numelements = m_pValueArray.size();
unsigned int i=0;
2002-10-12 11:37:38 +00:00
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++)
2002-10-12 11:37:38 +00:00
m_pValueArray[i]->Release();
m_pValueArray.clear();//.Clear();
}
CValue* CListValue::FindValue(const STR_String & name)
{
CValue* resultval = NULL;
int i=0;
while (!resultval && i < GetCount())
{
CValue* myval = GetValue(i);
if (myval->GetName() == name)
resultval = GetValue(i)->AddRef(); // add referencecount
else
i++;
}
return resultval;
}
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());
}
}
PyObject* CListValue::Pyappend(PyObject* value)
2002-10-12 11:37:38 +00:00
{
return listvalue_buffer_concat(m_proxy, value); /* m_proxy is the same as self */
2002-10-12 11:37:38 +00:00
}
PyObject* CListValue::Pyreverse()
2002-10-12 11:37:38 +00:00
{
std::reverse(m_pValueArray.begin(),m_pValueArray.end());
Py_RETURN_NONE;
2002-10-12 11:37:38 +00:00
}
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;
2002-10-12 11:37:38 +00:00
STR_String txt = eqval->GetText();
eqval->Release();
if (txt=="TRUE")
{
result = true;
}
return result;
}
PyObject* CListValue::Pyindex(PyObject *value)
2002-10-12 11:37:38 +00:00
{
PyObject* result = NULL;
CValue* checkobj = ConvertPythonToValue(value);
if (checkobj==NULL)
return NULL; /* ConvertPythonToValue sets the error */
int numelem = GetCount();
for (int i=0;i<numelem;i++)
2002-10-12 11:37:38 +00:00
{
CValue* elem = GetValue(i);
if (CheckEqual(checkobj,elem))
2002-10-12 11:37:38 +00:00
{
result = PyInt_FromLong(i);
break;
2002-10-12 11:37:38 +00:00
}
}
checkobj->Release();
2002-10-12 11:37:38 +00:00
if (result==NULL) {
PyErr_SetString(PyExc_ValueError, "list.index(x): x not in CListValue");
}
2002-10-12 11:37:38 +00:00
return result;
}
PyObject* CListValue::Pycount(PyObject* value)
2002-10-12 11:37:38 +00:00
{
int numfound = 0;
CValue* checkobj = ConvertPythonToValue(value);
if (checkobj==NULL) { /* in this case just return that there are no items in the list */
PyErr_Clear();
return PyInt_FromLong(0);
}
int numelem = GetCount();
for (int i=0;i<numelem;i++)
2002-10-12 11:37:38 +00:00
{
CValue* elem = GetValue(i);
if (CheckEqual(checkobj,elem))
2002-10-12 11:37:38 +00:00
{
numfound ++;
2002-10-12 11:37:38 +00:00
}
}
checkobj->Release();
2002-10-12 11:37:38 +00:00
return PyInt_FromLong(numfound);
}
PyObject* CListValue::Pyfrom_id(PyObject* value)
{
2009-04-19 17:26:03 +00:00
uintptr_t id= (uintptr_t)PyLong_AsVoidPtr(value);
if (PyErr_Occurred())
return NULL;
int numelem = GetCount();
for (int i=0;i<numelem;i++)
{
2009-04-19 17:26:03 +00:00
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;
}
2002-10-12 11:37:38 +00:00
/* ---------------------------------------------------------------------
* Some stuff taken from the header
* --------------------------------------------------------------------- */
CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val)
{
//assert(false); // todo: implement me!
fprintf(stderr, "CValueList::Calc not yet implimented\n");
2002-10-12 11:37:38 +00:00
return NULL;
}
CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype,
VALUE_OPERATOR op,
CValue* val)
{
//assert(false); // todo: implement me!
fprintf(stderr, "CValueList::CalcFinal not yet implimented\n");
2002-10-12 11:37:38 +00:00
return NULL;
}
void CListValue::Add(CValue* value)
{
m_pValueArray.push_back(value);
}
double CListValue::GetNumber()
2002-10-12 11:37:38 +00:00
{
return -1;
}
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;
}