diff options
author | Campbell Barton <ideasman42@gmail.com> | 2009-04-02 09:38:05 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2009-04-02 09:38:05 +0400 |
commit | fcc23faa3a5ec3c697e85e9a6b604ac7db80a05b (patch) | |
tree | 83203f4bdf0f56d6de7b659449aade290fe0d90b | |
parent | 48e4a4834092a8772141e6240e5e70d67110f126 (diff) |
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.
-rw-r--r-- | source/gameengine/Expressions/Value.cpp | 178 | ||||
-rw-r--r-- | source/gameengine/Expressions/Value.h | 6 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_GameObject.cpp | 76 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_GameObject.h | 8 |
4 files changed, 174 insertions, 94 deletions
diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp index ebb12636ac2..2ab0a9addee 100644 --- a/source/gameengine/Expressions/Value.cpp +++ b/source/gameengine/Expressions/Value.cpp @@ -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); diff --git a/source/gameengine/Expressions/Value.h b/source/gameengine/Expressions/Value.h index caf1064dc32..4678ab1f0c2 100644 --- a/source/gameengine/Expressions/Value.h +++ b/source/gameengine/Expressions/Value.h @@ -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 diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index bbfa2ad324f..281de1965d4 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -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 }; diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 326b3700ad7..774977f2ecf 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -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 : /** |