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