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