Added getitem/setitem access for KX_GameObject
ob.someProp = 10 can now be... ob["someProp"] = 10 For simple get/set test with an objects 10 properties, this is ~30% faster. Though I like the attribute access, its slower because it needs to lookup BGE attributes and methods (for parent classes as well as KX_GameObject class). This could also be an advantage if there are collisions between new attributes added for 2.49 and existing properties a game uses. Made some other small optimizations, - Getting and setting property can use const char* as well as STR_String (avoids making new STR_Strings just to do the lookup). - CValue::SetPropertiesModified() and CValue::SetPropertiesModified(), were looping through all items in the std::map, advancing from the beginning each time.
This commit is contained in:
@@ -320,55 +320,70 @@ STR_String CValue::op2str (VALUE_OPERATOR op)
|
||||
//
|
||||
void CValue::SetProperty(const STR_String & name,CValue* ioProperty)
|
||||
{
|
||||
// Check if somebody is setting an empty property
|
||||
if (ioProperty==NULL)
|
||||
{
|
||||
{ // Check if somebody is setting an empty property
|
||||
trace("Warning:trying to set empty property!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we have a property array
|
||||
if (m_pNamedPropertyArray == NULL)
|
||||
if (m_pNamedPropertyArray)
|
||||
{ // Try to replace property (if so -> exit as soon as we replaced it)
|
||||
CValue* oldval = (*m_pNamedPropertyArray)[name];
|
||||
if (oldval)
|
||||
oldval->Release();
|
||||
}
|
||||
else { // Make sure we have a property array
|
||||
m_pNamedPropertyArray = new std::map<STR_String,CValue *>;
|
||||
|
||||
// Try to replace property (if so -> exit as soon as we replaced it)
|
||||
CValue* oldval = (*m_pNamedPropertyArray)[name];
|
||||
if (oldval)
|
||||
{
|
||||
oldval->Release();
|
||||
}
|
||||
|
||||
// Add property at end of array
|
||||
(*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty);
|
||||
}
|
||||
|
||||
void CValue::SetProperty(const char* name,CValue* ioProperty)
|
||||
{
|
||||
if (ioProperty==NULL)
|
||||
{ // Check if somebody is setting an empty property
|
||||
trace("Warning:trying to set empty property!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pNamedPropertyArray)
|
||||
{ // Try to replace property (if so -> exit as soon as we replaced it)
|
||||
CValue* oldval = (*m_pNamedPropertyArray)[name];
|
||||
if (oldval)
|
||||
oldval->Release();
|
||||
}
|
||||
else { // Make sure we have a property array
|
||||
m_pNamedPropertyArray = new std::map<STR_String,CValue *>;
|
||||
}
|
||||
|
||||
// Add property at end of array
|
||||
(*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty);
|
||||
}
|
||||
|
||||
//
|
||||
// Get pointer to a property with name <inName>, returns NULL if there is no property named <inName>
|
||||
//
|
||||
CValue* CValue::GetProperty(const STR_String & inName)
|
||||
{
|
||||
// Check properties, as soon as we found it -> Return a pointer to the property
|
||||
CValue* result = NULL;
|
||||
if (m_pNamedPropertyArray)
|
||||
{
|
||||
std::map<STR_String,CValue*>::iterator it = (*m_pNamedPropertyArray).find(inName);
|
||||
if (!( it==m_pNamedPropertyArray->end()))
|
||||
{
|
||||
result = (*it).second;
|
||||
}
|
||||
|
||||
if (m_pNamedPropertyArray) {
|
||||
std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName);
|
||||
if (it != m_pNamedPropertyArray->end())
|
||||
return (*it).second;
|
||||
}
|
||||
//for (int i=0; i<m_pValuePropertyArray->size(); i++)
|
||||
// if ((*m_pValuePropertyArray)[i]->GetName() == inName)
|
||||
// return (*m_pValuePropertyArray)[i];
|
||||
|
||||
// Did not find property with name <inName>, return NULL property pointer
|
||||
return result;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
CValue* CValue::GetProperty(const char *inName)
|
||||
{
|
||||
if (m_pNamedPropertyArray) {
|
||||
std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName);
|
||||
if (it != m_pNamedPropertyArray->end())
|
||||
return (*it).second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Get text description of property with name <inName>, returns an empty string if there is no property named <inName>
|
||||
@@ -396,26 +411,20 @@ float CValue::GetPropertyNumber(const STR_String& inName,float defnumber)
|
||||
//
|
||||
// Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed
|
||||
//
|
||||
bool CValue::RemoveProperty(const STR_String & inName)
|
||||
bool CValue::RemoveProperty(const char *inName)
|
||||
{
|
||||
// Check if there are properties at all which can be removed
|
||||
if (m_pNamedPropertyArray) {
|
||||
CValue* val = GetProperty(inName);
|
||||
if (NULL != val)
|
||||
if (m_pNamedPropertyArray)
|
||||
{
|
||||
std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->find(inName);
|
||||
if (it != m_pNamedPropertyArray->end())
|
||||
{
|
||||
val->Release();
|
||||
m_pNamedPropertyArray->erase(inName);
|
||||
((*it).second)->Release();
|
||||
m_pNamedPropertyArray->erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char err[128];
|
||||
if (m_pNamedPropertyArray)
|
||||
sprintf(err, "attribute \"%s\" dosnt exist", inName.ReadPtr());
|
||||
else
|
||||
sprintf(err, "attribute \"%s\" dosnt exist (no property array)", inName.ReadPtr());
|
||||
|
||||
PyErr_SetString(PyExc_AttributeError, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -426,8 +435,8 @@ vector<STR_String> CValue::GetPropertyNames()
|
||||
{
|
||||
vector<STR_String> result;
|
||||
if(!m_pNamedPropertyArray) return result;
|
||||
for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin();
|
||||
!(it == m_pNamedPropertyArray->end());it++)
|
||||
std::map<STR_String,CValue*>::iterator it;
|
||||
for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
|
||||
{
|
||||
result.push_back((*it).first);
|
||||
}
|
||||
@@ -444,8 +453,8 @@ void CValue::ClearProperties()
|
||||
return;
|
||||
|
||||
// Remove all properties
|
||||
for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin();
|
||||
!(it == m_pNamedPropertyArray->end());it++)
|
||||
std::map<STR_String,CValue*>::iterator it;
|
||||
for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++)
|
||||
{
|
||||
CValue* tmpval = (*it).second;
|
||||
//STR_String name = (*it).first;
|
||||
@@ -464,9 +473,11 @@ void CValue::ClearProperties()
|
||||
//
|
||||
void CValue::SetPropertiesModified(bool inModified)
|
||||
{
|
||||
int numprops = GetPropertyCount();
|
||||
for (int i=0; i<numprops; i++)
|
||||
GetProperty(i)->SetModified(inModified);
|
||||
if(!m_pNamedPropertyArray) return;
|
||||
std::map<STR_String,CValue*>::iterator it;
|
||||
|
||||
for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++)
|
||||
((*it).second)->SetModified(inModified);
|
||||
}
|
||||
|
||||
|
||||
@@ -476,11 +487,13 @@ void CValue::SetPropertiesModified(bool inModified)
|
||||
//
|
||||
bool CValue::IsAnyPropertyModified()
|
||||
{
|
||||
int numprops = GetPropertyCount();
|
||||
for (int i=0;i<numprops;i++)
|
||||
if (GetProperty(i)->IsModified())
|
||||
if(!m_pNamedPropertyArray) return false;
|
||||
std::map<STR_String,CValue*>::iterator it;
|
||||
|
||||
for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++)
|
||||
if (((*it).second)->IsModified())
|
||||
return true;
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -489,7 +502,6 @@ bool CValue::IsAnyPropertyModified()
|
||||
//
|
||||
// Get property number <inIndex>
|
||||
//
|
||||
|
||||
CValue* CValue::GetProperty(int inIndex)
|
||||
{
|
||||
|
||||
@@ -498,8 +510,8 @@ CValue* CValue::GetProperty(int inIndex)
|
||||
|
||||
if (m_pNamedPropertyArray)
|
||||
{
|
||||
for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin();
|
||||
!(it == m_pNamedPropertyArray->end());it++)
|
||||
std::map<STR_String,CValue*>::iterator it;
|
||||
for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
|
||||
{
|
||||
if (count++==inIndex)
|
||||
{
|
||||
@@ -535,8 +547,8 @@ void CValue::CloneProperties(CValue *replica)
|
||||
if (m_pNamedPropertyArray)
|
||||
{
|
||||
replica->m_pNamedPropertyArray=NULL;
|
||||
for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin();
|
||||
!(it == m_pNamedPropertyArray->end());it++)
|
||||
std::map<STR_String,CValue*>::iterator it;
|
||||
for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
|
||||
{
|
||||
CValue *val = (*it).second->GetReplica();
|
||||
replica->SetProperty((*it).first,val);
|
||||
@@ -687,28 +699,15 @@ PyAttributeDef CValue::Attributes[] = {
|
||||
|
||||
PyObject* CValue::_getattr(const char *attr)
|
||||
{
|
||||
CValue* resultattr = FindIdentifier(STR_String(attr));
|
||||
STR_String text;
|
||||
CValue* resultattr = GetProperty(attr);
|
||||
if (resultattr)
|
||||
{
|
||||
if (resultattr->IsError())
|
||||
{
|
||||
resultattr->Release();
|
||||
} else
|
||||
{
|
||||
// to avoid some compare problems, return a real pythonthing
|
||||
PyObject* pyconvert = resultattr->ConvertValueToPython();
|
||||
if (pyconvert)
|
||||
{
|
||||
resultattr->Release();
|
||||
return pyconvert;
|
||||
} else
|
||||
{
|
||||
// also check if it's already in pythoninterpreter!
|
||||
return resultattr;
|
||||
}
|
||||
|
||||
}
|
||||
PyObject* pyconvert = resultattr->ConvertValueToPython();
|
||||
|
||||
if (pyconvert)
|
||||
return pyconvert;
|
||||
else
|
||||
return resultattr; // also check if it's already in pythoninterpreter!
|
||||
}
|
||||
_getattr_up(PyObjectPlus);
|
||||
}
|
||||
@@ -774,26 +773,25 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj)
|
||||
|
||||
int CValue::_delattr(const char *attr)
|
||||
{
|
||||
if (!RemoveProperty(STR_String(attr))) /* sets error */
|
||||
return 1;
|
||||
return 0;
|
||||
if (RemoveProperty(STR_String(attr)))
|
||||
return 0;
|
||||
|
||||
PyErr_Format(PyExc_AttributeError, "attribute \"%s\" dosnt exist", attr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CValue::_setattr(const char *attr,PyObject* pyobj)
|
||||
int CValue::_setattr(const char *attr, PyObject* pyobj)
|
||||
{
|
||||
CValue* vallie = ConvertPythonToValue(pyobj);
|
||||
if (vallie)
|
||||
{
|
||||
STR_String attr_str = attr;
|
||||
CValue* oldprop = GetProperty(attr_str);
|
||||
CValue* oldprop = GetProperty(attr);
|
||||
|
||||
if (oldprop)
|
||||
{
|
||||
oldprop->SetValue(vallie);
|
||||
} else
|
||||
{
|
||||
SetProperty(attr_str, vallie);
|
||||
}
|
||||
else
|
||||
SetProperty(attr, vallie);
|
||||
|
||||
vallie->Release();
|
||||
} else
|
||||
{
|
||||
@@ -811,8 +809,8 @@ PyObject* CValue::ConvertKeysToPython( void )
|
||||
|
||||
if (m_pNamedPropertyArray)
|
||||
{
|
||||
for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin();
|
||||
!(it == m_pNamedPropertyArray->end());it++)
|
||||
std::map<STR_String,CValue*>::iterator it;
|
||||
for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++)
|
||||
{
|
||||
pystr = PyString_FromString( (*it).first );
|
||||
PyList_Append(pylist, pystr);
|
||||
|
||||
@@ -283,10 +283,12 @@ public:
|
||||
|
||||
/// Property Management
|
||||
virtual void SetProperty(const STR_String& name,CValue* ioProperty); // Set property <ioProperty>, overwrites and releases a previous property with the same name if needed
|
||||
virtual CValue* GetProperty(const STR_String & inName); // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName>
|
||||
virtual void SetProperty(const char* name,CValue* ioProperty);
|
||||
virtual CValue* GetProperty(const char* inName); // Get pointer to a property with name <inName>, returns NULL if there is no property named <inName>
|
||||
virtual CValue* GetProperty(const STR_String & inName);
|
||||
STR_String GetPropertyText(const STR_String & inName,const STR_String& deftext=""); // Get text description of property with name <inName>, returns an empty string if there is no property named <inName>
|
||||
float GetPropertyNumber(const STR_String& inName,float defnumber);
|
||||
virtual bool RemoveProperty(const STR_String & inName); // Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed
|
||||
virtual bool RemoveProperty(const char *inName); // Remove the property named <inName>, returns true if the property was succesfully removed, false if property was not found or could not be removed
|
||||
virtual vector<STR_String> GetPropertyNames();
|
||||
virtual void ClearProperties(); // Clear all properties
|
||||
|
||||
|
||||
@@ -1103,6 +1103,80 @@ PyObject* KX_GameObject::PyGetPosition(PyObject* self)
|
||||
}
|
||||
|
||||
|
||||
int KX_GameObject::Map_Len(PyObject* self_v)
|
||||
{
|
||||
return (static_cast<KX_GameObject*>(self_v))->GetPropertyCount();
|
||||
}
|
||||
|
||||
|
||||
PyObject *KX_GameObject::Map_GetItem(PyObject *self_v, PyObject *item)
|
||||
{
|
||||
KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
|
||||
const char *attr= PyString_AsString(item);
|
||||
CValue* resultattr;
|
||||
PyObject* pyconvert;
|
||||
|
||||
|
||||
if(attr==NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "KX_GameObject key but a string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
resultattr = self->GetProperty(attr);
|
||||
|
||||
if(resultattr==NULL) {
|
||||
PyErr_SetString(PyExc_KeyError, "KX_GameObject key does not exist");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pyconvert = resultattr->ConvertValueToPython();
|
||||
|
||||
return pyconvert ? pyconvert:resultattr;
|
||||
}
|
||||
|
||||
|
||||
int KX_GameObject::Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val)
|
||||
{
|
||||
KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
|
||||
const char *attr= PyString_AsString(key);
|
||||
|
||||
if(attr==NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "KX_GameObject key but a string");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (val==NULL) { /* del ob["key"] */
|
||||
if (self->RemoveProperty(attr)==false) {
|
||||
PyErr_Format(PyExc_KeyError, "KX_GameObject key \"%s\" not found", attr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else { /* ob["key"] = value */
|
||||
CValue* vallie = self->ConvertPythonToValue(val);
|
||||
|
||||
if(vallie==NULL)
|
||||
return 1; /* ConvertPythonToValue sets the error */
|
||||
|
||||
CValue* oldprop = self->GetProperty(attr);
|
||||
|
||||
if (oldprop)
|
||||
oldprop->SetValue(vallie);
|
||||
else
|
||||
self->SetProperty(attr, vallie);
|
||||
|
||||
vallie->Release();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PyMappingMethods KX_GameObject::Mapping = {
|
||||
(inquiry)KX_GameObject::Map_Len, /*inquiry mp_length */
|
||||
(binaryfunc)KX_GameObject::Map_GetItem, /*binaryfunc mp_subscript */
|
||||
(objobjargproc)KX_GameObject::Map_SetItem, /*objobjargproc mp_ass_subscript */
|
||||
};
|
||||
|
||||
|
||||
PyTypeObject KX_GameObject::Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
@@ -1118,7 +1192,7 @@ PyTypeObject KX_GameObject::Type = {
|
||||
__repr,
|
||||
0, //&cvalue_as_number,
|
||||
0,
|
||||
0,
|
||||
&Mapping,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
@@ -822,7 +822,13 @@ public:
|
||||
static PyObject* pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
|
||||
static int pyattr_set_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
|
||||
|
||||
|
||||
/* getitem/setitem */
|
||||
static int Map_Len(PyObject* self);
|
||||
static PyMappingMethods Mapping;
|
||||
static PyObject* Map_GetItem(PyObject *self_v, PyObject *item);
|
||||
static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val);
|
||||
|
||||
|
||||
private :
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user