BGE C++ 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* 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, "list[i]: Python ListIndex out of range in CValueList");
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, "list[key]: '%s' key 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, "list.append(val): couldn't add one or more items to this CValueList");
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, "list.append(i): couldn't add item to this CValueList");
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(PyObjectPlus_Proxy), /*tp_basicsize*/
227         0,                              /*tp_itemsize*/
228         /* methods */
229         py_base_dealloc,                        /*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 PyObject* CListValue::py_getattro_dict() {
277         py_getattro_dict_up(CValue);
278 }
279
280
281 //////////////////////////////////////////////////////////////////////
282 // Construction/Destruction
283 //////////////////////////////////////////////////////////////////////
284
285 CListValue::CListValue(PyTypeObject *T ) 
286 : CPropValue(T)
287 {
288         m_bReleaseContents=true;        
289 }
290
291
292
293 CListValue::~CListValue()
294 {
295
296         if (m_bReleaseContents) {
297                 for (unsigned int i=0;i<m_pValueArray.size();i++) {
298                         m_pValueArray[i]->Release();
299                 }
300         }
301 }
302
303
304 static STR_String gstrListRep=STR_String("List");
305
306 const STR_String & CListValue::GetText()
307 {
308         gstrListRep = "[";
309         STR_String commastr = "";
310
311         for (int i=0;i<GetCount();i++)
312         {
313                 gstrListRep += commastr;
314                 gstrListRep += GetValue(i)->GetText();
315                 commastr = ",";
316         }
317         gstrListRep += "]";
318
319         return gstrListRep;
320 }
321
322
323
324 CValue* CListValue::GetReplica() { 
325         CListValue* replica = new CListValue(*this);
326
327         replica->ProcessReplica();
328
329         replica->m_bReleaseContents=true; // for copy, complete array is copied for now...
330         // copy all values
331         int numelements = m_pValueArray.size();
332         unsigned int i=0;
333         replica->m_pValueArray.resize(numelements);
334         for (i=0;i<m_pValueArray.size();i++)
335                 replica->m_pValueArray[i] = m_pValueArray[i]->GetReplica();
336
337
338         return replica;
339 };
340
341
342
343 void CListValue::SetValue(int i, CValue *val)
344 {
345         assertd(i < m_pValueArray.size());
346         m_pValueArray[i]=val;
347 }
348
349
350
351 void CListValue::Resize(int num)
352 {
353         m_pValueArray.resize(num);
354 }
355
356
357
358 void CListValue::Remove(int i)
359 {
360         assertd(i<m_pValueArray.size());
361         m_pValueArray.erase(m_pValueArray.begin()+i);
362 }
363
364
365
366 void CListValue::ReleaseAndRemoveAll()
367 {
368         for (unsigned int i=0;i<m_pValueArray.size();i++)
369                 m_pValueArray[i]->Release();
370         m_pValueArray.clear();//.Clear();
371 }
372
373
374
375 CValue* CListValue::FindValue(const STR_String & name)
376 {
377         CValue* resultval = NULL;
378         int i=0;
379         
380         while (!resultval && i < GetCount())
381         {
382                 CValue* myval = GetValue(i);
383                                 
384                 if (myval->GetName() == name)
385                         resultval = GetValue(i)->AddRef(); // add referencecount
386                 else
387                         i++;
388                 
389         }
390         return resultval;
391 }
392
393
394
395 bool CListValue::SearchValue(CValue *val)
396 {
397         for (int i=0;i<GetCount();i++)
398                 if (val == GetValue(i))
399                         return true;
400         return false;
401 }
402
403
404
405 void CListValue::SetReleaseOnDestruct(bool bReleaseContents)
406 {
407         m_bReleaseContents = bReleaseContents;
408 }
409
410
411
412 bool CListValue::RemoveValue(CValue *val)
413 {
414         bool result=false;
415
416         for (int i=GetCount()-1;i>=0;i--)
417                 if (val == GetValue(i))
418                 {
419                         Remove(i);
420                         result=true;
421                 }
422         return result;
423 }
424
425
426
427 void CListValue::MergeList(CListValue *otherlist)
428 {
429
430         int numelements = this->GetCount();
431         int numotherelements = otherlist->GetCount();
432
433
434         Resize(numelements+numotherelements);
435
436         for (int i=0;i<numotherelements;i++)
437         {
438                 SetValue(i+numelements,otherlist->GetValue(i)->AddRef());
439         }
440
441 }
442
443
444
445 PyObject* CListValue::Pyappend(PyObject* value)
446 {
447         return listvalue_buffer_concat(m_proxy, value); /* m_proxy is the same as self */
448 }
449
450
451
452 PyObject* CListValue::Pyreverse()
453 {
454         std::reverse(m_pValueArray.begin(),m_pValueArray.end());
455         Py_RETURN_NONE;
456 }
457
458
459
460 bool CListValue::CheckEqual(CValue* first,CValue* second)
461 {
462         bool result = false;
463
464         CValue* eqval =  ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second);
465         
466         if (eqval==NULL)
467                 return false;
468                 
469         STR_String txt = eqval->GetText();
470         eqval->Release();
471         if (txt=="TRUE")
472         {
473                 result = true;
474         }
475         return result;
476
477 }
478
479
480
481 PyObject* CListValue::Pyindex(PyObject *value)
482 {
483         PyObject* result = NULL;
484
485         CValue* checkobj = ConvertPythonToValue(value);
486         if (checkobj==NULL)
487                 return NULL; /* ConvertPythonToValue sets the error */
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                         result = PyInt_FromLong(i);
496                         break;
497                 }
498         }
499         checkobj->Release();
500
501         if (result==NULL) {
502                 PyErr_SetString(PyExc_ValueError, "list.index(x): x not in CListValue");
503         }
504         return result;
505         
506 }
507
508
509
510 PyObject* CListValue::Pycount(PyObject* value)
511 {
512         int numfound = 0;
513
514         CValue* checkobj = ConvertPythonToValue(value);
515         
516         if (checkobj==NULL) { /* in this case just return that there are no items in the list */
517                 PyErr_Clear();
518                 return PyInt_FromLong(0);
519         }
520
521         int numelem = GetCount();
522         for (int i=0;i<numelem;i++)
523         {
524                 CValue* elem =                  GetValue(i);
525                 if (CheckEqual(checkobj,elem))
526                 {
527                         numfound ++;
528                 }
529         }
530         checkobj->Release();
531
532         return PyInt_FromLong(numfound);
533 }
534
535
536
537 PyObject* CListValue::Pyfrom_id(PyObject* value)
538 {
539         uintptr_t id= (uintptr_t)PyLong_AsVoidPtr(value);
540         
541         if (PyErr_Occurred())
542                 return NULL;
543
544         int numelem = GetCount();
545         for (int i=0;i<numelem;i++)
546         {
547                 if (reinterpret_cast<uintptr_t>(m_pValueArray[i]->m_proxy) == id)
548                         return GetValue(i)->GetProxy();
549         }
550         PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in CValueList");
551         return NULL;    
552
553 }
554
555
556 /* --------------------------------------------------------------------- 
557  * Some stuff taken from the header
558  * --------------------------------------------------------------------- */
559 CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val) 
560 {
561         //assert(false); // todo: implement me!
562         fprintf(stderr, "CValueList::Calc not yet implimented\n");
563         return NULL;
564 }
565
566
567
568 CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype,
569                                                           VALUE_OPERATOR op, 
570                                                           CValue* val) 
571 {
572         //assert(false); // todo: implement me!
573         fprintf(stderr, "CValueList::CalcFinal not yet implimented\n");
574         return NULL;
575 }
576
577
578
579 void CListValue::Add(CValue* value)
580 {
581         m_pValueArray.push_back(value);
582 }
583
584
585
586 double CListValue::GetNumber()
587 {
588         return -1;
589 }
590
591
592
593 void CListValue::SetModified(bool bModified)
594 {       
595         CValue::SetModified(bModified);
596         int numels = GetCount();
597
598         for (int i=0;i<numels;i++)
599                 GetValue(i)->SetModified(bModified);
600 }
601
602
603
604 bool CListValue::IsModified()
605 {
606         bool bmod = CValue::IsModified(); //normal own flag
607         int numels = GetCount();
608
609         for (int i=0;i<numels;i++)
610                 bmod = bmod || GetValue(i)->IsModified();
611
612         return bmod;
613 }