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