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