Added getitem/setitem access for KX_GameObject
authorCampbell Barton <ideasman42@gmail.com>
Thu, 2 Apr 2009 05:38:05 +0000 (05:38 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 2 Apr 2009 05:38:05 +0000 (05:38 +0000)
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.

source/gameengine/Expressions/Value.cpp
source/gameengine/Expressions/Value.h
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_GameObject.h

index ebb12636ac2cc65ce91c353fa18cec2871b5e0b5..2ab0a9addee9ac463be1f2ebd3d514b94f1cc9be 100644 (file)
@@ -320,55 +320,70 @@ STR_String CValue::op2str (VALUE_OPERATOR op)
 //
 void CValue::SetProperty(const STR_String & name,CValue* ioProperty)
 {
 //
 void CValue::SetProperty(const STR_String & name,CValue* ioProperty)
 {
-       // Check if somebody is setting an empty property
        if (ioProperty==NULL)
        if (ioProperty==NULL)
-       {
+       {       // Check if somebody is setting an empty property
                trace("Warning:trying to set empty property!");
                return;
        }
 
                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 *>;
                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);
 }
 
        }
        
        // 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)
 {
 
 //
 // 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>
 
 //
 // 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
 //
 //
 // 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
 {
        // 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;
                }
                        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;
 }
 
        return false;
 }
 
@@ -426,8 +435,8 @@ vector<STR_String> CValue::GetPropertyNames()
 {
        vector<STR_String> result;
        if(!m_pNamedPropertyArray) return result;
 {
        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);
        }
        {
                result.push_back((*it).first);
        }
@@ -444,8 +453,8 @@ void CValue::ClearProperties()
                return;
 
        // Remove all properties
                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;
        {
                CValue* tmpval = (*it).second;
                //STR_String name = (*it).first;
@@ -464,9 +473,11 @@ void CValue::ClearProperties()
 //
 void CValue::SetPropertiesModified(bool inModified)
 {
 //
 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()
 {
 //
 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 true;
-
+       
        return false;
 }
 
        return false;
 }
 
@@ -489,7 +502,6 @@ bool CValue::IsAnyPropertyModified()
 //
 // Get property number <inIndex>
 //
 //
 // Get property number <inIndex>
 //
-
 CValue* CValue::GetProperty(int inIndex)
 {
 
 CValue* CValue::GetProperty(int inIndex)
 {
 
@@ -498,8 +510,8 @@ CValue* CValue::GetProperty(int inIndex)
 
        if (m_pNamedPropertyArray)
        {
 
        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)
                        {
                {
                        if (count++==inIndex)
                        {
@@ -535,8 +547,8 @@ void CValue::CloneProperties(CValue *replica)
        if (m_pNamedPropertyArray)
        {
                replica->m_pNamedPropertyArray=NULL;
        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);
                {
                        CValue *val = (*it).second->GetReplica();
                        replica->SetProperty((*it).first,val);
@@ -687,28 +699,15 @@ PyAttributeDef CValue::Attributes[] = {
 
 PyObject*      CValue::_getattr(const char *attr)
 {
 
 PyObject*      CValue::_getattr(const char *attr)
 {
-       CValue* resultattr = FindIdentifier(STR_String(attr));
-       STR_String text;
+       CValue* resultattr = GetProperty(attr);
        if (resultattr)
        {
        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);
 }
        }
        _getattr_up(PyObjectPlus);
 }
@@ -774,26 +773,25 @@ CValue* CValue::ConvertPythonToValue(PyObject* pyobj)
 
 int    CValue::_delattr(const char *attr)
 {
 
 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)
        {
 {
        CValue* vallie = ConvertPythonToValue(pyobj);
        if (vallie)
        {
-               STR_String attr_str = attr;
-               CValue* oldprop = GetProperty(attr_str);
+               CValue* oldprop = GetProperty(attr);
                
                if (oldprop)
                
                if (oldprop)
-               {
                        oldprop->SetValue(vallie);
                        oldprop->SetValue(vallie);
-               } else
-               {
-                       SetProperty(attr_str, vallie);
-               }
+               else
+                       SetProperty(attr, vallie);
+               
                vallie->Release();
        } else
        {
                vallie->Release();
        } else
        {
@@ -811,8 +809,8 @@ PyObject*   CValue::ConvertKeysToPython( void )
        
        if (m_pNamedPropertyArray)
        {
        
        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);
                {
                        pystr = PyString_FromString( (*it).first );
                        PyList_Append(pylist, pystr);
index caf1064dc32e4f438a8ccd30f718811a5f23e009..4678ab1f0c29890abeefc32dcd1b42a6bc6722ad 100644 (file)
@@ -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
 
        /// 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);
        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
 
        virtual vector<STR_String>      GetPropertyNames();
        virtual void            ClearProperties();                                                                              // Clear all properties
 
index bbfa2ad324fb8a923076b94df94d1ed6156ec18a..281de1965d41f3fa37632a9f48442b7a053ab6a2 100644 (file)
@@ -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)
 
 PyTypeObject KX_GameObject::Type = {
        PyObject_HEAD_INIT(&PyType_Type)
@@ -1118,7 +1192,7 @@ PyTypeObject KX_GameObject::Type = {
                __repr,
                0, //&cvalue_as_number,
                0,
                __repr,
                0, //&cvalue_as_number,
                0,
-               0,
+               &Mapping,
                0,
                0
 };
                0,
                0
 };
index 326b3700ad7ab863e55cb9bc8b2eab29aac2f6e4..774977f2ecf7b02f8c6d863be137551d592b6ef9 100644 (file)
@@ -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);
        
        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 :
 
        /**     
 private :
 
        /**