BGE Python API
[blender.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(NULL)
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         0,                      /*tp_getattr*/
205         0,                      /*tp_setattr*/
206         0,                              /*tp_compare*/
207         py_base_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,
214         py_base_getattro,
215         py_base_setattro,
216         0,0,0,0,0,0,0,0,0,
217         Methods
218 };
219
220
221
222 PyParentObject CListValue::Parents[] = {
223         &CListValue::Type,
224         &CValue::Type,
225                 NULL
226 };
227
228
229
230
231 PyMethodDef CListValue::Methods[] = {
232         {"append", (PyCFunction)CListValue::sPyappend,METH_O},
233         {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS},
234         {"index", (PyCFunction)CListValue::sPyindex,METH_O},
235         {"count", (PyCFunction)CListValue::sPycount,METH_O},
236         
237         {NULL,NULL} //Sentinel
238 };
239
240 PyAttributeDef CListValue::Attributes[] = {
241         { NULL }        //Sentinel
242 };
243
244 PyObject* CListValue::py_getattro(PyObject* attr) {
245         py_getattro_up(CValue);
246 }
247
248
249 //////////////////////////////////////////////////////////////////////
250 // Construction/Destruction
251 //////////////////////////////////////////////////////////////////////
252
253 CListValue::CListValue(PyTypeObject *T ) 
254 : CPropValue(T)
255 {
256         m_bReleaseContents=true;        
257 }
258
259
260
261 CListValue::~CListValue()
262 {
263
264         if (m_bReleaseContents) {
265                 for (unsigned int i=0;i<m_pValueArray.size();i++) {
266                         m_pValueArray[i]->Release();
267                 }
268         }
269 }
270
271
272 static STR_String gstrListRep=STR_String("List");
273
274 const STR_String & CListValue::GetText()
275 {
276         gstrListRep = "[";
277         STR_String commastr = "";
278
279         for (int i=0;i<GetCount();i++)
280         {
281                 gstrListRep += commastr;
282                 gstrListRep += GetValue(i)->GetText();
283                 commastr = ",";
284         }
285         gstrListRep += "]";
286
287         return gstrListRep;
288 }
289
290
291
292 CValue* CListValue::GetReplica() { 
293         CListValue* replica = new CListValue(*this);
294
295         CValue::AddDataToReplica(replica);
296
297         replica->m_bReleaseContents=true; // for copy, complete array is copied for now...
298         // copy all values
299         int numelements = m_pValueArray.size();
300         unsigned int i=0;
301         replica->m_pValueArray.resize(numelements);
302         for (i=0;i<m_pValueArray.size();i++)
303                 replica->m_pValueArray[i] = m_pValueArray[i]->GetReplica();
304
305
306         return replica;
307 };
308
309
310
311 void CListValue::SetValue(int i, CValue *val)
312 {
313         assertd(i < m_pValueArray.size());
314         m_pValueArray[i]=val;
315 }
316
317
318
319 void CListValue::Resize(int num)
320 {
321         m_pValueArray.resize(num);
322 }
323
324
325
326 void CListValue::Remove(int i)
327 {
328         assertd(i<m_pValueArray.size());
329         m_pValueArray.erase(m_pValueArray.begin()+i);
330 }
331
332
333
334 void CListValue::ReleaseAndRemoveAll()
335 {
336         for (unsigned int i=0;i<m_pValueArray.size();i++)
337                 m_pValueArray[i]->Release();
338         m_pValueArray.clear();//.Clear();
339 }
340
341
342
343 CValue* CListValue::FindValue(const STR_String & name)
344 {
345         CValue* resultval = NULL;
346         int i=0;
347         
348         while (!resultval && i < GetCount())
349         {
350                 CValue* myval = GetValue(i);
351                                 
352                 if (myval->GetName() == name)
353                         resultval = GetValue(i)->AddRef(); // add referencecount
354                 else
355                         i++;
356                 
357         }
358         return resultval;
359 }
360
361
362
363 bool CListValue::SearchValue(CValue *val)
364 {
365         for (int i=0;i<GetCount();i++)
366                 if (val == GetValue(i))
367                         return true;
368         return false;
369 }
370
371
372
373 void CListValue::SetReleaseOnDestruct(bool bReleaseContents)
374 {
375         m_bReleaseContents = bReleaseContents;
376 }
377
378
379
380 bool CListValue::RemoveValue(CValue *val)
381 {
382         bool result=false;
383
384         for (int i=GetCount()-1;i>=0;i--)
385                 if (val == GetValue(i))
386                 {
387                         Remove(i);
388                         result=true;
389                 }
390         return result;
391 }
392
393
394
395 void CListValue::MergeList(CListValue *otherlist)
396 {
397
398         int numelements = this->GetCount();
399         int numotherelements = otherlist->GetCount();
400
401
402         Resize(numelements+numotherelements);
403
404         for (int i=0;i<numotherelements;i++)
405         {
406                 SetValue(i+numelements,otherlist->GetValue(i)->AddRef());
407         }
408
409 }
410
411
412
413 PyObject* CListValue::Pyappend(PyObject* self, PyObject* value)
414 {
415         return listvalue_buffer_concat(self, value);
416 }
417
418
419
420 PyObject* CListValue::Pyreverse(PyObject* self)
421 {
422         std::reverse(m_pValueArray.begin(),m_pValueArray.end());
423         Py_RETURN_NONE;
424 }
425
426
427
428 bool CListValue::CheckEqual(CValue* first,CValue* second)
429 {
430         bool result = false;
431
432         CValue* eqval =  ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second);
433         
434         if (eqval==NULL)
435                 return false;
436                 
437         STR_String txt = eqval->GetText();
438         eqval->Release();
439         if (txt=="TRUE")
440         {
441                 result = true;
442         }
443         return result;
444
445 }
446
447
448
449 PyObject* CListValue::Pyindex(PyObject* self, PyObject *value)
450 {
451         PyObject* result = NULL;
452
453         CValue* checkobj = ConvertPythonToValue(value);
454         if (checkobj==NULL)
455                 return NULL; /* ConvertPythonToValue sets the error */
456
457         int numelem = GetCount();
458         for (int i=0;i<numelem;i++)
459         {
460                 CValue* elem =                  GetValue(i);
461                 if (CheckEqual(checkobj,elem))
462                 {
463                         result = PyInt_FromLong(i);
464                         break;
465                 }
466         }
467         checkobj->Release();
468
469         if (result==NULL) {
470                 PyErr_SetString(PyExc_ValueError, "ValueError: list.index(x): x not in CListValue");
471         }
472         return result;
473         
474 }
475
476
477
478 PyObject* CListValue::Pycount(PyObject* self, PyObject* value)
479 {
480         int numfound = 0;
481
482         CValue* checkobj = ConvertPythonToValue(value);
483         
484         if (checkobj==NULL) { /* in this case just return that there are no items in the list */
485                 PyErr_Clear();
486                 return PyInt_FromLong(0);
487         }
488
489         int numelem = GetCount();
490         for (int i=0;i<numelem;i++)
491         {
492                 CValue* elem =                  GetValue(i);
493                 if (CheckEqual(checkobj,elem))
494                 {
495                         numfound ++;
496                 }
497         }
498         checkobj->Release();
499
500         return PyInt_FromLong(numfound);
501 }
502
503
504
505 /* --------------------------------------------------------------------- 
506  * Some stuff taken from the header
507  * --------------------------------------------------------------------- */
508 CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val) 
509 {
510         //assert(false); // todo: implement me!
511         fprintf(stderr, "CValueList::Calc not yet implimented\n");
512         return NULL;
513 }
514
515
516
517 CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype,
518                                                           VALUE_OPERATOR op, 
519                                                           CValue* val) 
520 {
521         //assert(false); // todo: implement me!
522         fprintf(stderr, "CValueList::CalcFinal not yet implimented\n");
523         return NULL;
524 }
525
526
527
528 void CListValue::Add(CValue* value)
529 {
530         m_pValueArray.push_back(value);
531 }
532
533
534
535 float CListValue::GetNumber()
536 {
537         return -1;
538 }
539
540
541
542 void CListValue::SetModified(bool bModified)
543 {       
544         CValue::SetModified(bModified);
545         int numels = GetCount();
546
547         for (int i=0;i<numels;i++)
548                 GetValue(i)->SetModified(bModified);
549 }
550
551
552
553 bool CListValue::IsModified()
554 {
555         bool bmod = CValue::IsModified(); //normal own flag
556         int numels = GetCount();
557
558         for (int i=0;i<numels;i++)
559                 bmod = bmod || GetValue(i)->IsModified();
560
561         return bmod;
562 }