2.50:
[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
213
214 static  PySequenceMethods listvalue_as_sequence = {
215         listvalue_bufferlen,//(inquiry)buffer_length, /*sq_length*/
216         listvalue_buffer_concat, /*sq_concat*/
217         NULL, /*sq_repeat*/
218         listvalue_buffer_item, /*sq_item*/
219 #if (PY_VERSION_HEX >= 0x03000000) // TODO, slicing in py3?
220         NULL,
221         NULL,
222         NULL,
223 #else
224         listvalue_buffer_slice, /*sq_slice*/
225         NULL, /*sq_ass_item*/
226         NULL, /*sq_ass_slice*/
227 #endif
228 };
229
230
231
232 /* Is this one used ? */
233 static  PyMappingMethods instance_as_mapping = {
234         listvalue_bufferlen, /*mp_length*/
235         listvalue_mapping_subscript, /*mp_subscript*/
236         NULL /*mp_ass_subscript*/
237 };
238
239
240
241 PyTypeObject CListValue::Type = {
242 #if (PY_VERSION_HEX >= 0x02060000)
243         PyVarObject_HEAD_INIT(NULL, 0)
244 #else
245         /* python 2.5 and below */
246         PyObject_HEAD_INIT( NULL )  /* required py macro */
247         0,                              /*ob_size*/
248 #endif
249         "CListValue",                   /*tp_name*/
250         sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/
251         0,                              /*tp_itemsize*/
252         /* methods */
253         py_base_dealloc,                        /*tp_dealloc*/
254         0,                              /*tp_print*/
255         0,                      /*tp_getattr*/
256         0,                      /*tp_setattr*/
257         0,                              /*tp_compare*/
258         py_base_repr,                           /*tp_repr*/
259         0,                              /*tp_as_number*/
260         &listvalue_as_sequence, /*tp_as_sequence*/
261         &instance_as_mapping,           /*tp_as_mapping*/
262         0,                              /*tp_hash*/
263         0,                              /*tp_call */
264         0,
265         py_base_getattro,
266         py_base_setattro,
267         0,0,0,0,0,0,0,0,0,
268         Methods
269 };
270
271
272
273 PyParentObject CListValue::Parents[] = {
274         &CListValue::Type,
275         &CValue::Type,
276                 NULL
277 };
278
279
280
281
282 PyMethodDef CListValue::Methods[] = {
283         /* List style access */
284         {"append", (PyCFunction)CListValue::sPyappend,METH_O},
285         {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS},
286         {"index", (PyCFunction)CListValue::sPyindex,METH_O},
287         {"count", (PyCFunction)CListValue::sPycount,METH_O},
288         
289         /* Dict style access */
290         {"get", (PyCFunction)CListValue::sPyget,METH_VARARGS},
291         {"has_key", (PyCFunction)CListValue::sPyhas_key,METH_O},
292         
293         /* Own cvalue funcs */
294         {"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O},
295         
296         {NULL,NULL} //Sentinel
297 };
298
299 PyAttributeDef CListValue::Attributes[] = {
300         { NULL }        //Sentinel
301 };
302
303 PyObject* CListValue::py_getattro(PyObject* attr) {
304         py_getattro_up(CValue);
305 }
306
307 PyObject* CListValue::py_getattro_dict() {
308         py_getattro_dict_up(CValue);
309 }
310
311
312 //////////////////////////////////////////////////////////////////////
313 // Construction/Destruction
314 //////////////////////////////////////////////////////////////////////
315
316 CListValue::CListValue(PyTypeObject *T ) 
317 : CPropValue(T)
318 {
319         m_bReleaseContents=true;        
320 }
321
322
323
324 CListValue::~CListValue()
325 {
326
327         if (m_bReleaseContents) {
328                 for (unsigned int i=0;i<m_pValueArray.size();i++) {
329                         m_pValueArray[i]->Release();
330                 }
331         }
332 }
333
334
335 static STR_String gstrListRep=STR_String("List");
336
337 const STR_String & CListValue::GetText()
338 {
339         gstrListRep = "[";
340         STR_String commastr = "";
341
342         for (int i=0;i<GetCount();i++)
343         {
344                 gstrListRep += commastr;
345                 gstrListRep += GetValue(i)->GetText();
346                 commastr = ",";
347         }
348         gstrListRep += "]";
349
350         return gstrListRep;
351 }
352
353
354
355 CValue* CListValue::GetReplica() { 
356         CListValue* replica = new CListValue(*this);
357
358         replica->ProcessReplica();
359
360         replica->m_bReleaseContents=true; // for copy, complete array is copied for now...
361         // copy all values
362         int numelements = m_pValueArray.size();
363         unsigned int i=0;
364         replica->m_pValueArray.resize(numelements);
365         for (i=0;i<m_pValueArray.size();i++)
366                 replica->m_pValueArray[i] = m_pValueArray[i]->GetReplica();
367
368
369         return replica;
370 };
371
372
373
374 void CListValue::SetValue(int i, CValue *val)
375 {
376         assertd(i < m_pValueArray.size());
377         m_pValueArray[i]=val;
378 }
379
380
381
382 void CListValue::Resize(int num)
383 {
384         m_pValueArray.resize(num);
385 }
386
387
388
389 void CListValue::Remove(int i)
390 {
391         assertd(i<m_pValueArray.size());
392         m_pValueArray.erase(m_pValueArray.begin()+i);
393 }
394
395
396
397 void CListValue::ReleaseAndRemoveAll()
398 {
399         for (unsigned int i=0;i<m_pValueArray.size();i++)
400                 m_pValueArray[i]->Release();
401         m_pValueArray.clear();//.Clear();
402 }
403
404
405
406 CValue* CListValue::FindValue(const STR_String & name)
407 {
408         for (int i=0; i < GetCount(); i++)
409                 if (GetValue(i)->GetName() == name)
410                         return GetValue(i);
411         
412         return NULL;
413 }
414
415 CValue* CListValue::FindValue(const char * name)
416 {
417         for (int i=0; i < GetCount(); i++)
418                 if (GetValue(i)->GetName() == name)
419                         return GetValue(i);
420         
421         return NULL;
422 }
423
424 bool CListValue::SearchValue(CValue *val)
425 {
426         for (int i=0;i<GetCount();i++)
427                 if (val == GetValue(i))
428                         return true;
429         return false;
430 }
431
432
433
434 void CListValue::SetReleaseOnDestruct(bool bReleaseContents)
435 {
436         m_bReleaseContents = bReleaseContents;
437 }
438
439
440
441 bool CListValue::RemoveValue(CValue *val)
442 {
443         bool result=false;
444
445         for (int i=GetCount()-1;i>=0;i--)
446                 if (val == GetValue(i))
447                 {
448                         Remove(i);
449                         result=true;
450                 }
451         return result;
452 }
453
454
455
456 void CListValue::MergeList(CListValue *otherlist)
457 {
458
459         int numelements = this->GetCount();
460         int numotherelements = otherlist->GetCount();
461
462
463         Resize(numelements+numotherelements);
464
465         for (int i=0;i<numotherelements;i++)
466         {
467                 SetValue(i+numelements,otherlist->GetValue(i)->AddRef());
468         }
469 }
470
471
472 PyObject* CListValue::Pyappend(PyObject* value)
473 {
474         CValue* objval = ConvertPythonToValue(value, "CList.append(i): CValueList, ");
475
476         if (!objval) /* ConvertPythonToValue sets the error */
477                 return NULL;
478         
479         if (!BGE_PROXY_PYOWNS(m_proxy)) {
480                 PyErr_SetString(PyExc_TypeError, "CList.append(i): this CValueList is used internally for the game engine and can't be modified");
481                 return NULL;
482         }
483         
484         Add(objval);
485         
486         Py_RETURN_NONE;
487 }
488
489
490
491 PyObject* CListValue::Pyreverse()
492 {
493         std::reverse(m_pValueArray.begin(),m_pValueArray.end());
494         Py_RETURN_NONE;
495 }
496
497
498
499 bool CListValue::CheckEqual(CValue* first,CValue* second)
500 {
501         bool result = false;
502
503         CValue* eqval =  ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second);
504         
505         if (eqval==NULL)
506                 return false;
507         const STR_String& text = eqval->GetText();
508         if (&text==&CBoolValue::sTrueString)
509         {
510                 result = true;
511         }
512         eqval->Release();
513         return result;
514
515 }
516
517
518
519 PyObject* CListValue::Pyindex(PyObject *value)
520 {
521         PyObject* result = NULL;
522
523         CValue* checkobj = ConvertPythonToValue(value, "val = cList[i]: CValueList, ");
524         if (checkobj==NULL)
525                 return NULL; /* ConvertPythonToValue sets the error */
526
527         int numelem = GetCount();
528         for (int i=0;i<numelem;i++)
529         {
530                 CValue* elem =                  GetValue(i);
531                 if (CheckEqual(checkobj,elem))
532                 {
533                         result = PyInt_FromLong(i);
534                         break;
535                 }
536         }
537         checkobj->Release();
538
539         if (result==NULL) {
540                 PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in CListValue");
541         }
542         return result;
543         
544 }
545
546
547
548 PyObject* CListValue::Pycount(PyObject* value)
549 {
550         int numfound = 0;
551
552         CValue* checkobj = ConvertPythonToValue(value, ""); /* error ignored */
553         
554         if (checkobj==NULL) { /* in this case just return that there are no items in the list */
555                 PyErr_Clear();
556                 return PyInt_FromLong(0);
557         }
558
559         int numelem = GetCount();
560         for (int i=0;i<numelem;i++)
561         {
562                 CValue* elem =                  GetValue(i);
563                 if (CheckEqual(checkobj,elem))
564                 {
565                         numfound ++;
566                 }
567         }
568         checkobj->Release();
569
570         return PyInt_FromLong(numfound);
571 }
572
573 /* Matches python dict.get(key, [default]) */
574 PyObject* CListValue::Pyget(PyObject *args)
575 {
576         char *key;
577         PyObject* def = Py_None;
578
579         if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
580                 return NULL;
581         
582         CValue *item = FindValue((const char *)key);
583         if (item) {     
584                 PyObject* pyobj = item->ConvertValueToPython();
585                 if (pyobj)
586                         return pyobj;
587                 else
588                         return item->GetProxy();
589         }
590         Py_INCREF(def);
591         return def;
592 }
593
594 /* Matches python dict.has_key() */
595 PyObject* CListValue::Pyhas_key(PyObject* value)
596 {
597         if (PyString_Check(value) && FindValue((const char *)PyString_AsString(value)))
598                 Py_RETURN_TRUE;
599         
600         Py_RETURN_FALSE;
601 }
602
603 PyObject* CListValue::Pyfrom_id(PyObject* value)
604 {
605         uintptr_t id= (uintptr_t)PyLong_AsVoidPtr(value);
606         
607         if (PyErr_Occurred())
608                 return NULL;
609
610         int numelem = GetCount();
611         for (int i=0;i<numelem;i++)
612         {
613                 if (reinterpret_cast<uintptr_t>(m_pValueArray[i]->m_proxy) == id)
614                         return GetValue(i)->GetProxy();
615         }
616         PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in CValueList");
617         return NULL;    
618
619 }
620
621
622 /* --------------------------------------------------------------------- 
623  * Some stuff taken from the header
624  * --------------------------------------------------------------------- */
625 CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val) 
626 {
627         //assert(false); // todo: implement me!
628         static int error_printed =  0;
629         if (error_printed==0) {
630                 fprintf(stderr, "CValueList::Calc not yet implimented\n");
631                 error_printed = 1;
632         }
633         return NULL;
634 }
635
636 CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype,
637                                                           VALUE_OPERATOR op, 
638                                                           CValue* val) 
639 {
640         //assert(false); // todo: implement me!
641         static int error_printed =  0;
642         if (error_printed==0) {
643                 fprintf(stderr, "CValueList::CalcFinal not yet implimented\n");
644                 error_printed = 1;
645         }
646         return NULL;
647 }
648
649
650
651 void CListValue::Add(CValue* value)
652 {
653         m_pValueArray.push_back(value);
654 }
655
656
657
658 double CListValue::GetNumber()
659 {
660         return -1;
661 }
662
663
664
665 void CListValue::SetModified(bool bModified)
666 {       
667         CValue::SetModified(bModified);
668         int numels = GetCount();
669
670         for (int i=0;i<numels;i++)
671                 GetValue(i)->SetModified(bModified);
672 }
673
674
675
676 bool CListValue::IsModified()
677 {
678         bool bmod = CValue::IsModified(); //normal own flag
679         int numels = GetCount();
680
681         for (int i=0;i<numels;i++)
682                 bmod = bmod || GetValue(i)->IsModified();
683
684         return bmod;
685 }