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