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