BGE Python api
[blender-staging.git] / source / gameengine / Expressions / ListValue.cpp
1 // ListValue.cpp: implementation of the CListValue class.
2 //
3 //////////////////////////////////////////////////////////////////////
4 /*
5  * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org>
6  *
7  * Permission to use, copy, modify, distribute and sell this software
8  * and its documentation for any purpose is hereby granted without fee,
9  * provided that the above copyright notice appear in all copies and
10  * that both that copyright notice and this permission notice appear
11  * in supporting documentation.  Erwin Coumans makes no
12  * representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied warranty.
14  *
15  */
16
17 #include "ListValue.h"
18 #include "StringValue.h"
19 #include "VoidValue.h"
20 #include <algorithm>
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #if  ((PY_MAJOR_VERSION == 2) &&(PY_MINOR_VERSION < 5))
27 #define Py_ssize_t int
28 #endif
29
30 Py_ssize_t listvalue_bufferlen(PyObject* list)
31 {
32         return (Py_ssize_t)( ((CListValue*)list)->GetCount());
33 }
34
35 PyObject* listvalue_buffer_item(PyObject* list,Py_ssize_t index)
36 {
37         int count = ((CListValue*) list)->GetCount();
38         
39         if (index < 0)
40                 index = count+index;
41         
42         if (index >= 0 && index < count)
43         {
44                 PyObject* pyobj = ((CListValue*) list)->GetValue(index)->ConvertValueToPython();
45                 if (pyobj)
46                         return pyobj;
47                 else
48                         return ((CListValue*) list)->GetValue(index)->AddRef();
49
50         }
51         PyErr_SetString(PyExc_IndexError, "Python ListIndex out of range");
52         return NULL;
53 }
54
55 PyObject* listvalue_mapping_subscript(PyObject* list,PyObject* pyindex)
56 {
57         if (PyString_Check(pyindex))
58         {
59                 STR_String  index(PyString_AsString(pyindex));
60                 CValue *item = ((CListValue*) list)->FindValue(index);
61                 if (item)
62                         return (PyObject*) item;
63                         
64         }
65         if (PyInt_Check(pyindex))
66         {
67                 int index = PyInt_AsLong(pyindex);
68                 return listvalue_buffer_item(list, index);
69         }
70         
71         PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */
72         PyErr_Format(PyExc_KeyError, "'%s' not in list", PyString_AsString(pyindex_str));
73         Py_DECREF(pyindex_str);
74         return NULL;
75 }
76
77
78 /* just slice it into a python list... */
79 PyObject* listvalue_buffer_slice(PyObject* list,Py_ssize_t ilow, Py_ssize_t ihigh)
80 {
81         int i, j;
82         PyListObject *newlist;
83
84         if (ilow < 0) ilow = 0;
85
86         int n = ((CListValue*) list)->GetCount();
87
88         if (ihigh >= n)
89                 ihigh = n;
90     if (ihigh < ilow)
91         ihigh = ilow;
92
93         newlist = (PyListObject *) PyList_New(ihigh - ilow);
94         if (!newlist)
95                 return NULL;
96
97         for (i = ilow, j = 0; i < ihigh; i++, j++)
98         {
99                 PyObject* pyobj = ((CListValue*) list)->GetValue(i)->ConvertValueToPython();
100                 if (!pyobj)
101                         pyobj = ((CListValue*) list)->GetValue(i)->AddRef();
102                 newlist->ob_item[j] = pyobj;
103         }       
104         return (PyObject *) newlist;
105 }
106
107
108
109 static PyObject *
110 listvalue_buffer_concat(PyObject * self, PyObject * other)
111 {
112         // for now, we support CListValue concatenated with items
113         // and CListValue concatenated to Python Lists
114         // and CListValue concatenated with another CListValue
115
116         CListValue* listval = (CListValue*) self;
117         listval->AddRef();
118         if (other->ob_type == &PyList_Type)
119         {
120                 bool error = false;
121
122                 int i;
123                 int numitems = PyList_Size(other);
124                 for (i=0;i<numitems;i++)
125                 {
126                         PyObject* listitem = PyList_GetItem(other,i);
127                         CValue* listitemval = listval->ConvertPythonToValue(listitem);
128                         if (listitemval)
129                         {
130                                 listval->Add(listitemval);
131                         } else
132                         {
133                                 error = true;
134                         }
135                 }
136
137                 if (error) {
138                         PyErr_SetString(PyExc_SystemError, "Python Error: couldn't add one or more items to a list");
139                         return NULL;
140                 }
141
142         } else
143         {
144                 if (other->ob_type == &CListValue::Type)
145                 {
146                         // add items from otherlist to this list
147                         CListValue* otherval = (CListValue*) other;
148                         
149
150                         for (int i=0;i<otherval->GetCount();i++)
151                         {
152                                 otherval->Add(listval->GetValue(i)->AddRef());
153                         }
154                 }
155                 else
156                 {
157                         CValue* objval = listval->ConvertPythonToValue(other);
158                         if (objval)
159                         {
160                                 listval->Add(objval);
161                         } else
162                         {
163                                 PyErr_SetString(PyExc_SystemError, "Python Error: couldn't add item to a list");  
164                                 return NULL;
165                         }
166                 }
167         }
168
169         return self;
170 }
171
172
173
174 static  PySequenceMethods listvalue_as_sequence = {
175         listvalue_bufferlen,//(inquiry)buffer_length, /*sq_length*/
176         listvalue_buffer_concat, /*sq_concat*/
177         NULL, /*sq_repeat*/
178         listvalue_buffer_item, /*sq_item*/
179         listvalue_buffer_slice, /*sq_slice*/
180         NULL, /*sq_ass_item*/
181         NULL /*sq_ass_slice*/
182 };
183
184
185
186 /* Is this one used ? */
187 static  PyMappingMethods instance_as_mapping = {
188         listvalue_bufferlen, /*mp_length*/
189         listvalue_mapping_subscript, /*mp_subscript*/
190         NULL /*mp_ass_subscript*/
191 };
192
193
194
195 PyTypeObject CListValue::Type = {
196         PyObject_HEAD_INIT(&PyType_Type)
197         0,                              /*ob_size*/
198         "CListValue",                   /*tp_name*/
199         sizeof(CListValue),             /*tp_basicsize*/
200         0,                              /*tp_itemsize*/
201         /* methods */
202         PyDestructor,                   /*tp_dealloc*/
203         0,                              /*tp_print*/
204         __getattr,                      /*tp_getattr*/
205         __setattr,                      /*tp_setattr*/
206         0,                              /*tp_compare*/
207         __repr,                         /*tp_repr*/
208         0,                              /*tp_as_number*/
209         &listvalue_as_sequence, /*tp_as_sequence*/
210         &instance_as_mapping,           /*tp_as_mapping*/
211         0,                              /*tp_hash*/
212         0,                              /*tp_call */
213         0,0,0,0,0,0,0,0,0,0,0,0,
214         Methods
215 };
216
217
218
219 PyParentObject CListValue::Parents[] = {
220         &CListValue::Type,
221         &CValue::Type,
222                 NULL
223 };
224
225
226
227
228 PyMethodDef CListValue::Methods[] = {
229         {"append", (PyCFunction)CListValue::sPyappend,METH_O},
230         {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS},
231         {"index", (PyCFunction)CListValue::sPyindex,METH_O},
232         {"count", (PyCFunction)CListValue::sPycount,METH_O},
233         
234         {NULL,NULL} //Sentinel
235 };
236
237 PyAttributeDef CListValue::Attributes[] = {
238         { NULL }        //Sentinel
239 };
240
241 PyObject* CListValue::_getattr(const char *attr) {
242         _getattr_up(CValue);
243 }
244
245
246 //////////////////////////////////////////////////////////////////////
247 // Construction/Destruction
248 //////////////////////////////////////////////////////////////////////
249
250 CListValue::CListValue(PyTypeObject *T ) 
251 : CPropValue(T)
252 {
253         m_bReleaseContents=true;        
254 }
255
256
257
258 CListValue::~CListValue()
259 {
260
261         if (m_bReleaseContents) {
262                 for (unsigned int i=0;i<m_pValueArray.size();i++) {
263                         m_pValueArray[i]->Release();
264                 }
265         }
266 }
267
268
269 static STR_String gstrListRep=STR_String("List");
270
271 const STR_String & CListValue::GetText()
272 {
273         gstrListRep = "[";
274         STR_String commastr = "";
275
276         for (int i=0;i<GetCount();i++)
277         {
278                 gstrListRep += commastr;
279                 gstrListRep += GetValue(i)->GetText();
280                 commastr = ",";
281         }
282         gstrListRep += "]";
283
284         return gstrListRep;
285 }
286
287
288
289 CValue* CListValue::GetReplica() { 
290         CListValue* replica = new CListValue(*this);
291
292         CValue::AddDataToReplica(replica);
293
294         replica->m_bReleaseContents=true; // for copy, complete array is copied for now...
295         // copy all values
296         int numelements = m_pValueArray.size();
297         unsigned int i=0;
298         replica->m_pValueArray.resize(numelements);
299         for (i=0;i<m_pValueArray.size();i++)
300                 replica->m_pValueArray[i] = m_pValueArray[i]->GetReplica();
301
302
303         return replica;
304 };
305
306
307
308 void CListValue::SetValue(int i, CValue *val)
309 {
310         assertd(i < m_pValueArray.size());
311         m_pValueArray[i]=val;
312 }
313
314
315
316 void CListValue::Resize(int num)
317 {
318         m_pValueArray.resize(num);
319 }
320
321
322
323 void CListValue::Remove(int i)
324 {
325         assertd(i<m_pValueArray.size());
326         m_pValueArray.erase(m_pValueArray.begin()+i);
327 }
328
329
330
331 void CListValue::ReleaseAndRemoveAll()
332 {
333         for (unsigned int i=0;i<m_pValueArray.size();i++)
334                 m_pValueArray[i]->Release();
335         m_pValueArray.clear();//.Clear();
336 }
337
338
339
340 CValue* CListValue::FindValue(const STR_String & name)
341 {
342         CValue* resultval = NULL;
343         int i=0;
344         
345         while (!resultval && i < GetCount())
346         {
347                 CValue* myval = GetValue(i);
348                                 
349                 if (myval->GetName() == name)
350                         resultval = GetValue(i)->AddRef(); // add referencecount
351                 else
352                         i++;
353                 
354         }
355         return resultval;
356 }
357
358
359
360 bool CListValue::SearchValue(CValue *val)
361 {
362         for (int i=0;i<GetCount();i++)
363                 if (val == GetValue(i))
364                         return true;
365         return false;
366 }
367
368
369
370 void CListValue::SetReleaseOnDestruct(bool bReleaseContents)
371 {
372         m_bReleaseContents = bReleaseContents;
373 }
374
375
376
377 bool CListValue::RemoveValue(CValue *val)
378 {
379         bool result=false;
380
381         for (int i=GetCount()-1;i>=0;i--)
382                 if (val == GetValue(i))
383                 {
384                         Remove(i);
385                         result=true;
386                 }
387         return result;
388 }
389
390
391
392 void CListValue::MergeList(CListValue *otherlist)
393 {
394
395         int numelements = this->GetCount();
396         int numotherelements = otherlist->GetCount();
397
398
399         Resize(numelements+numotherelements);
400
401         for (int i=0;i<numotherelements;i++)
402         {
403                 SetValue(i+numelements,otherlist->GetValue(i)->AddRef());
404         }
405
406 }
407
408
409
410 PyObject* CListValue::Pyappend(PyObject* self, PyObject* value)
411 {
412         return listvalue_buffer_concat(self, value);
413 }
414
415
416
417 PyObject* CListValue::Pyreverse(PyObject* self)
418 {
419         std::reverse(m_pValueArray.begin(),m_pValueArray.end());
420         Py_RETURN_NONE;
421 }
422
423
424
425 bool CListValue::CheckEqual(CValue* first,CValue* second)
426 {
427         bool result = false;
428
429         CValue* eqval =  ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second);
430         STR_String txt = eqval->GetText();
431         eqval->Release();
432         if (txt=="TRUE")
433         {
434                 result = true;
435         }
436         return result;
437
438 }
439
440
441
442 PyObject* CListValue::Pyindex(PyObject* self, PyObject *value)
443 {
444         PyObject* result = NULL;
445
446         CValue* checkobj = ConvertPythonToValue(value);
447         if (checkobj==NULL)
448                 return NULL; /* ConvertPythonToValue sets the error */
449
450         int numelem = GetCount();
451         for (int i=0;i<numelem;i++)
452         {
453                 CValue* elem =                  GetValue(i);
454                 if (CheckEqual(checkobj,elem))
455                 {
456                         result = PyInt_FromLong(i);
457                         break;
458                 }
459         }
460         checkobj->Release();
461
462         if (result==NULL) {
463                 PyErr_SetString(PyExc_ValueError, "ValueError: list.index(x): x not in CListValue");
464         }
465         return result;
466         
467 }
468
469
470
471 PyObject* CListValue::Pycount(PyObject* self, PyObject* value)
472 {
473         int numfound = 0;
474
475         CValue* checkobj = ConvertPythonToValue(value);
476         
477         if (checkobj==NULL) { /* in this case just return that there are no items in the list */
478                 PyErr_Clear();
479                 PyInt_FromLong(0);
480         }
481
482         int numelem = GetCount();
483         for (int i=0;i<numelem;i++)
484         {
485                 CValue* elem =                  GetValue(i);
486                 if (CheckEqual(checkobj,elem))
487                 {
488                         numfound ++;
489                 }
490         }
491         checkobj->Release();
492
493         return PyInt_FromLong(numfound);
494 }
495
496
497
498 /* --------------------------------------------------------------------- 
499  * Some stuff taken from the header
500  * --------------------------------------------------------------------- */
501 CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val) 
502 {
503         assert(false); // todo: implement me!
504         return NULL;
505 }
506
507
508
509 CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype,
510                                                           VALUE_OPERATOR op, 
511                                                           CValue* val) 
512 {
513         assert(false); // todo: implement me!
514         return NULL;
515 }
516
517
518
519 void CListValue::Add(CValue* value)
520 {
521         m_pValueArray.push_back(value);
522 }
523
524
525
526 float CListValue::GetNumber()
527 {
528         return -1;
529 }
530
531
532
533 void CListValue::SetModified(bool bModified)
534 {       
535         CValue::SetModified(bModified);
536         int numels = GetCount();
537
538         for (int i=0;i<numels;i++)
539                 GetValue(i)->SetModified(bModified);
540 }
541
542
543
544 bool CListValue::IsModified()
545 {
546         bool bmod = CValue::IsModified(); //normal own flag
547         int numels = GetCount();
548
549         for (int i=0;i<numels;i++)
550                 bmod = bmod || GetValue(i)->IsModified();
551
552         return bmod;
553 }