Merge with trunk r37757.
[blender.git] / source / gameengine / Expressions / ListValue.cpp
index c78963142d1eb3ab84b8605a1c6d39f9af0c798e..271d5067dd9733352db35173e43d2797013b1dfa 100644 (file)
@@ -1,3 +1,6 @@
+/** \file gameengine/Expressions/ListValue.cpp
+ *  \ingroup expressions
+ */
 // ListValue.cpp: implementation of the CListValue class.
 //
 //////////////////////////////////////////////////////////////////////
  *
  */
 
+#include <stdio.h>
+
 #include "ListValue.h"
 #include "StringValue.h"
 #include "VoidValue.h"
 #include <algorithm>
+#include "BoolValue.h"
+
+#include "BLO_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 implimented\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 implimented\n");
+               error_printed = 1;
+       }
+       return NULL;
+}
+
+
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+void CListValue::Add(CValue* value)
+{
+       m_pValueArray.push_back(value);
+}
+
+
+
+double CListValue::GetNumber()
+{
+       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;
+}
 
-#if  ((PY_MAJOR_VERSION == 2) &&(PY_MINOR_VERSION < 5))
-#define Py_ssize_t int
-#endif
+#ifdef WITH_PYTHON
+
+/* --------------------------------------------------------------------- */
+/* Python interface ---------------------------------------------------- */
+/* --------------------------------------------------------------------- */
 
 Py_ssize_t listvalue_bufferlen(PyObject* self)
 {
@@ -73,22 +323,25 @@ PyObject* listvalue_mapping_subscript(PyObject* self, PyObject* pyindex)
                return NULL;
        }
        
-       if (PyString_Check(pyindex))
+       if (PyUnicode_Check(pyindex))
        {
-               STR_String  index(PyString_AsString(pyindex));
-               CValue *item = ((CListValue*) list)->FindValue(index);
-               if (item)
-                       return item->GetProxy();
-                       
+               CValue *item = ((CListValue*) list)->FindValue(_PyUnicode_AsString(pyindex));
+               if (item) {
+                       PyObject* pyobj = item->ConvertValueToPython();
+                       if(pyobj)
+                               return pyobj;
+                       else
+                               return item->GetProxy();
+               }
        }
-       if (PyInt_Check(pyindex))
+       else if (PyLong_Check(pyindex))
        {
-               int index = PyInt_AsLong(pyindex);
-               return listvalue_buffer_item(self, index);
+               int index = PyLong_AsSsize_t(pyindex);
+               return listvalue_buffer_item(self, index); /* wont add a ref */
        }
        
        PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */
-       PyErr_Format(PyExc_KeyError, "CList[key]: '%s' key not in list", PyString_AsString(pyindex_str));
+       PyErr_Format(PyExc_KeyError, "CList[key]: '%s' key not in list", _PyUnicode_AsString(pyindex_str));
        Py_DECREF(pyindex_str);
        return NULL;
 }
@@ -112,8 +365,8 @@ PyObject* listvalue_buffer_slice(PyObject* self,Py_ssize_t ilow, Py_ssize_t ihig
 
        if (ihigh >= n)
                ihigh = n;
-    if (ihigh < ilow)
-        ihigh = ilow;
+       if (ihigh < ilow)
+               ihigh = ilow;
 
        newlist = PyList_New(ihigh - ilow);
        if (!newlist)
@@ -205,6 +458,30 @@ static PyObject *listvalue_buffer_concat(PyObject * self, PyObject * other)
        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 = {
@@ -212,9 +489,13 @@ static  PySequenceMethods listvalue_as_sequence = {
        listvalue_buffer_concat, /*sq_concat*/
        NULL, /*sq_repeat*/
        listvalue_buffer_item, /*sq_item*/
-       listvalue_buffer_slice, /*sq_slice*/
+// TODO, slicing in py3
+       NULL, // listvalue_buffer_slice, /*sq_slice*/
        NULL, /*sq_ass_item*/
-       NULL /*sq_ass_slice*/
+       NULL, /*sq_ass_slice*/
+       (objobjproc)listvalue_buffer_contains,  /* sq_contains */
+       (binaryfunc) NULL, /* sq_inplace_concat */
+       (ssizeargfunc) NULL, /* sq_inplace_repeat */
 };
 
 
@@ -229,8 +510,7 @@ static  PyMappingMethods instance_as_mapping = {
 
 
 PyTypeObject CListValue::Type = {
-       PyObject_HEAD_INIT(NULL)
-       0,                              /*ob_size*/
+       PyVarObject_HEAD_INIT(NULL, 0)
        "CListValue",                   /*tp_name*/
        sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/
        0,                              /*tp_itemsize*/
@@ -247,30 +527,32 @@ PyTypeObject CListValue::Type = {
        0,                              /*tp_hash*/
        0,                              /*tp_call */
        0,
-       py_base_getattro,
-       py_base_setattro,
-       0,0,0,0,0,0,0,0,0,
-       Methods
-};
-
-
-
-PyParentObject CListValue::Parents[] = {
-       &CListValue::Type,
+       NULL,
+       NULL,
+       0,
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+       0,0,0,0,0,0,0,
+       Methods,
+       0,
+       0,
        &CValue::Type,
-               NULL
+       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
 };
 
@@ -278,225 +560,29 @@ PyAttributeDef CListValue::Attributes[] = {
        { NULL }        //Sentinel
 };
 
-PyObject* CListValue::py_getattro(PyObject* attr) {
-       py_getattro_up(CValue);
-}
-
-PyObject* CListValue::py_getattro_dict() {
-       py_getattro_dict_up(CValue);
-}
-
-
-//////////////////////////////////////////////////////////////////////
-// 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++) {
-                       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)
-{
-       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)
 {
        CValue* objval = ConvertPythonToValue(value, "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): this CValueList is used internally for the game engine and can't be modified");
                return NULL;
        }
-       
+
        Add(objval);
-       
+
        Py_RETURN_NONE;
 }
 
-
-
 PyObject* CListValue::Pyreverse()
 {
        std::reverse(m_pValueArray.begin(),m_pValueArray.end());
        Py_RETURN_NONE;
 }
 
-
-
-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;
-               
-       STR_String txt = eqval->GetText();
-       eqval->Release();
-       if (txt=="TRUE")
-       {
-               result = true;
-       }
-       return result;
-
-}
-
-
-
 PyObject* CListValue::Pyindex(PyObject *value)
 {
        PyObject* result = NULL;
@@ -509,9 +595,9 @@ PyObject* CListValue::Pyindex(PyObject *value)
        for (int i=0;i<numelem;i++)
        {
                CValue* elem =                  GetValue(i);
-               if (CheckEqual(checkobj,elem))
+               if (checkobj==elem || CheckEqual(checkobj,elem))
                {
-                       result = PyInt_FromLong(i);
+                       result = PyLong_FromSsize_t(i);
                        break;
                }
        }
@@ -521,7 +607,7 @@ PyObject* CListValue::Pyindex(PyObject *value)
                PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in CListValue");
        }
        return result;
-       
+
 }
 
 
@@ -530,33 +616,53 @@ PyObject* CListValue::Pycount(PyObject* value)
 {
        int numfound = 0;
 
-       CValue* checkobj = ConvertPythonToValue(value, "cList.count(val): CValueList, ");
-       
+       CValue* checkobj = ConvertPythonToValue(value, ""); /* error ignored */
+
        if (checkobj==NULL) { /* in this case just return that there are no items in the list */
                PyErr_Clear();
-               return PyInt_FromLong(0);
+               return PyLong_FromSsize_t(0);
        }
 
        int numelem = GetCount();
        for (int i=0;i<numelem;i++)
        {
                CValue* elem =                  GetValue(i);
-               if (CheckEqual(checkobj,elem))
+               if (checkobj==elem || CheckEqual(checkobj,elem))
                {
                        numfound ++;
                }
        }
        checkobj->Release();
 
-       return PyInt_FromLong(numfound);
+       return PyLong_FromSsize_t(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;
 
@@ -567,66 +673,8 @@ PyObject* CListValue::Pyfrom_id(PyObject* value)
                        return GetValue(i)->GetProxy();
        }
        PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in CValueList");
-       return NULL;    
-
-}
-
-
-/* --------------------------------------------------------------------- 
- * 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");
        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");
-       return NULL;
-}
-
-
-
-void CListValue::Add(CValue* value)
-{
-       m_pValueArray.push_back(value);
-}
 
-
-
-double CListValue::GetNumber()
-{
-       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;
-}
+#endif // WITH_PYTHON