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