use long long rather then int for storing game logic properties.
[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* list)
31 {
32         return (Py_ssize_t)( ((CListValue*)list)->GetCount());
33 }
34
35 PyObject* listvalue_buffer_item(PyObject* list,Py_ssize_t index)
36 {
37         int count = ((CListValue*) list)->GetCount();
38         
39         if (index < 0)
40                 index = count+index;
41         
42         if (index >= 0 && index < count)
43         {
44                 PyObject* pyobj = ((CListValue*) list)->GetValue(index)->ConvertValueToPython();
45                 if (pyobj)
46                         return pyobj;
47                 else
48                         return ((CListValue*) list)->GetValue(index)->AddRef();
49
50         }
51         PyErr_SetString(PyExc_IndexError, "Python ListIndex out of range");
52         return NULL;
53 }
54
55 PyObject* listvalue_mapping_subscript(PyObject* list,PyObject* pyindex)
56 {
57         if (PyString_Check(pyindex))
58         {
59                 STR_String  index(PyString_AsString(pyindex));
60                 CValue *item = ((CListValue*) list)->FindValue(index);
61                 if (item)
62                         return (PyObject*) item;
63                         
64         }
65         if (PyInt_Check(pyindex))
66         {
67                 int index = PyInt_AsLong(pyindex);
68                 return listvalue_buffer_item(list, index);
69         }
70         
71         PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */
72         PyErr_Format(PyExc_KeyError, "'%s' not in list", PyString_AsString(pyindex_str));
73         Py_DECREF(pyindex_str);
74         return NULL;
75 }
76
77
78 /* just slice it into a python list... */
79 PyObject* listvalue_buffer_slice(PyObject* list,Py_ssize_t ilow, Py_ssize_t ihigh)
80 {
81         int i, j;
82         PyListObject *newlist;
83
84         if (ilow < 0) ilow = 0;
85
86         int n = ((CListValue*) list)->GetCount();
87
88         if (ihigh >= n)
89                 ihigh = n;
90     if (ihigh < ilow)
91         ihigh = ilow;
92
93         newlist = (PyListObject *) PyList_New(ihigh - ilow);
94         if (!newlist)
95                 return NULL;
96
97         for (i = ilow, j = 0; i < ihigh; i++, j++)
98         {
99                 PyObject* pyobj = ((CListValue*) list)->GetValue(i)->ConvertValueToPython();
100                 if (!pyobj)
101                         pyobj = ((CListValue*) list)->GetValue(i)->AddRef();
102                 newlist->ob_item[j] = pyobj;
103         }       
104         return (PyObject *) newlist;
105 }
106
107
108
109 static PyObject *
110 listvalue_buffer_concat(PyObject * self, PyObject * other)
111 {
112         // for now, we support CListValue concatenated with items
113         // and CListValue concatenated to Python Lists
114         // and CListValue concatenated with another CListValue
115
116         CListValue* listval = (CListValue*) self;
117         listval->AddRef();
118         if (other->ob_type == &PyList_Type)
119         {
120                 bool error = false;
121
122                 int i;
123                 int numitems = PyList_Size(other);
124                 for (i=0;i<numitems;i++)
125                 {
126                         PyObject* listitem = PyList_GetItem(other,i);
127                         CValue* listitemval = listval->ConvertPythonToValue(listitem);
128                         if (listitemval)
129                         {
130                                 listval->Add(listitemval);
131                         } else
132                         {
133                                 error = true;
134                         }
135                 }
136
137                 if (error) {
138                         PyErr_SetString(PyExc_SystemError, "Python Error: couldn't add one or more items to a list");
139                         return NULL;
140                 }
141
142         } else
143         {
144                 if (other->ob_type == &CListValue::Type)
145                 {
146                         // add items from otherlist to this list
147                         CListValue* otherval = (CListValue*) other;
148                         
149
150                         for (int i=0;i<otherval->GetCount();i++)
151                         {
152                                 otherval->Add(listval->GetValue(i)->AddRef());
153                         }
154                 }
155                 else
156                 {
157                         CValue* objval = listval->ConvertPythonToValue(other);
158                         if (objval)
159                         {
160                                 listval->Add(objval);
161                         } else
162                         {
163                                 PyErr_SetString(PyExc_SystemError, "Python Error: couldn't add item to a list");  
164                                 return NULL;
165                         }
166                 }
167         }
168
169         return self;
170 }
171
172
173
174 static  PySequenceMethods listvalue_as_sequence = {
175         listvalue_bufferlen,//(inquiry)buffer_length, /*sq_length*/
176         listvalue_buffer_concat, /*sq_concat*/
177         NULL, /*sq_repeat*/
178         listvalue_buffer_item, /*sq_item*/
179         listvalue_buffer_slice, /*sq_slice*/
180         NULL, /*sq_ass_item*/
181         NULL /*sq_ass_slice*/
182 };
183
184
185
186 /* Is this one used ? */
187 static  PyMappingMethods instance_as_mapping = {
188         listvalue_bufferlen, /*mp_length*/
189         listvalue_mapping_subscript, /*mp_subscript*/
190         NULL /*mp_ass_subscript*/
191 };
192
193
194
195 PyTypeObject CListValue::Type = {
196         PyObject_HEAD_INIT(NULL)
197         0,                              /*ob_size*/
198         "CListValue",                   /*tp_name*/
199         sizeof(CListValue),             /*tp_basicsize*/
200         0,                              /*tp_itemsize*/
201         /* methods */
202         PyDestructor,                   /*tp_dealloc*/
203         0,                              /*tp_print*/
204         0,                      /*tp_getattr*/
205         0,                      /*tp_setattr*/
206         0,                              /*tp_compare*/
207         py_base_repr,                           /*tp_repr*/
208         0,                              /*tp_as_number*/
209         &listvalue_as_sequence, /*tp_as_sequence*/
210         &instance_as_mapping,           /*tp_as_mapping*/
211         0,                              /*tp_hash*/
212         0,                              /*tp_call */
213         0,
214         py_base_getattro,
215         py_base_setattro,
216         0,0,0,0,0,0,0,0,0,
217         Methods
218 };
219
220
221
222 PyParentObject CListValue::Parents[] = {
223         &CListValue::Type,
224         &CValue::Type,
225                 NULL
226 };
227
228
229
230
231 PyMethodDef CListValue::Methods[] = {
232         {"append", (PyCFunction)CListValue::sPyappend,METH_O},
233         {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS},
234         {"index", (PyCFunction)CListValue::sPyindex,METH_O},
235         {"count", (PyCFunction)CListValue::sPycount,METH_O},
236         {"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O},
237         
238         {NULL,NULL} //Sentinel
239 };
240
241 PyAttributeDef CListValue::Attributes[] = {
242         { NULL }        //Sentinel
243 };
244
245 PyObject* CListValue::py_getattro(PyObject* attr) {
246         py_getattro_up(CValue);
247 }
248
249
250 //////////////////////////////////////////////////////////////////////
251 // Construction/Destruction
252 //////////////////////////////////////////////////////////////////////
253
254 CListValue::CListValue(PyTypeObject *T ) 
255 : CPropValue(T)
256 {
257         m_bReleaseContents=true;        
258 }
259
260
261
262 CListValue::~CListValue()
263 {
264
265         if (m_bReleaseContents) {
266                 for (unsigned int i=0;i<m_pValueArray.size();i++) {
267                         m_pValueArray[i]->Release();
268                 }
269         }
270 }
271
272
273 static STR_String gstrListRep=STR_String("List");
274
275 const STR_String & CListValue::GetText()
276 {
277         gstrListRep = "[";
278         STR_String commastr = "";
279
280         for (int i=0;i<GetCount();i++)
281         {
282                 gstrListRep += commastr;
283                 gstrListRep += GetValue(i)->GetText();
284                 commastr = ",";
285         }
286         gstrListRep += "]";
287
288         return gstrListRep;
289 }
290
291
292
293 CValue* CListValue::GetReplica() { 
294         CListValue* replica = new CListValue(*this);
295
296         CValue::AddDataToReplica(replica);
297
298         replica->m_bReleaseContents=true; // for copy, complete array is copied for now...
299         // copy all values
300         int numelements = m_pValueArray.size();
301         unsigned int i=0;
302         replica->m_pValueArray.resize(numelements);
303         for (i=0;i<m_pValueArray.size();i++)
304                 replica->m_pValueArray[i] = m_pValueArray[i]->GetReplica();
305
306
307         return replica;
308 };
309
310
311
312 void CListValue::SetValue(int i, CValue *val)
313 {
314         assertd(i < m_pValueArray.size());
315         m_pValueArray[i]=val;
316 }
317
318
319
320 void CListValue::Resize(int num)
321 {
322         m_pValueArray.resize(num);
323 }
324
325
326
327 void CListValue::Remove(int i)
328 {
329         assertd(i<m_pValueArray.size());
330         m_pValueArray.erase(m_pValueArray.begin()+i);
331 }
332
333
334
335 void CListValue::ReleaseAndRemoveAll()
336 {
337         for (unsigned int i=0;i<m_pValueArray.size();i++)
338                 m_pValueArray[i]->Release();
339         m_pValueArray.clear();//.Clear();
340 }
341
342
343
344 CValue* CListValue::FindValue(const STR_String & name)
345 {
346         CValue* resultval = NULL;
347         int i=0;
348         
349         while (!resultval && i < GetCount())
350         {
351                 CValue* myval = GetValue(i);
352                                 
353                 if (myval->GetName() == name)
354                         resultval = GetValue(i)->AddRef(); // add referencecount
355                 else
356                         i++;
357                 
358         }
359         return resultval;
360 }
361
362
363
364 bool CListValue::SearchValue(CValue *val)
365 {
366         for (int i=0;i<GetCount();i++)
367                 if (val == GetValue(i))
368                         return true;
369         return false;
370 }
371
372
373
374 void CListValue::SetReleaseOnDestruct(bool bReleaseContents)
375 {
376         m_bReleaseContents = bReleaseContents;
377 }
378
379
380
381 bool CListValue::RemoveValue(CValue *val)
382 {
383         bool result=false;
384
385         for (int i=GetCount()-1;i>=0;i--)
386                 if (val == GetValue(i))
387                 {
388                         Remove(i);
389                         result=true;
390                 }
391         return result;
392 }
393
394
395
396 void CListValue::MergeList(CListValue *otherlist)
397 {
398
399         int numelements = this->GetCount();
400         int numotherelements = otherlist->GetCount();
401
402
403         Resize(numelements+numotherelements);
404
405         for (int i=0;i<numotherelements;i++)
406         {
407                 SetValue(i+numelements,otherlist->GetValue(i)->AddRef());
408         }
409
410 }
411
412
413
414 PyObject* CListValue::Pyappend(PyObject* self, PyObject* value)
415 {
416         return listvalue_buffer_concat(self, value);
417 }
418
419
420
421 PyObject* CListValue::Pyreverse(PyObject* self)
422 {
423         std::reverse(m_pValueArray.begin(),m_pValueArray.end());
424         Py_RETURN_NONE;
425 }
426
427
428
429 bool CListValue::CheckEqual(CValue* first,CValue* second)
430 {
431         bool result = false;
432
433         CValue* eqval =  ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second);
434         
435         if (eqval==NULL)
436                 return false;
437                 
438         STR_String txt = eqval->GetText();
439         eqval->Release();
440         if (txt=="TRUE")
441         {
442                 result = true;
443         }
444         return result;
445
446 }
447
448
449
450 PyObject* CListValue::Pyindex(PyObject* self, PyObject *value)
451 {
452         PyObject* result = NULL;
453
454         CValue* checkobj = ConvertPythonToValue(value);
455         if (checkobj==NULL)
456                 return NULL; /* ConvertPythonToValue sets the error */
457
458         int numelem = GetCount();
459         for (int i=0;i<numelem;i++)
460         {
461                 CValue* elem =                  GetValue(i);
462                 if (CheckEqual(checkobj,elem))
463                 {
464                         result = PyInt_FromLong(i);
465                         break;
466                 }
467         }
468         checkobj->Release();
469
470         if (result==NULL) {
471                 PyErr_SetString(PyExc_ValueError, "ValueError: list.index(x): x not in CListValue");
472         }
473         return result;
474         
475 }
476
477
478
479 PyObject* CListValue::Pycount(PyObject* self, PyObject* value)
480 {
481         int numfound = 0;
482
483         CValue* checkobj = ConvertPythonToValue(value);
484         
485         if (checkobj==NULL) { /* in this case just return that there are no items in the list */
486                 PyErr_Clear();
487                 return PyInt_FromLong(0);
488         }
489
490         int numelem = GetCount();
491         for (int i=0;i<numelem;i++)
492         {
493                 CValue* elem =                  GetValue(i);
494                 if (CheckEqual(checkobj,elem))
495                 {
496                         numfound ++;
497                 }
498         }
499         checkobj->Release();
500
501         return PyInt_FromLong(numfound);
502 }
503
504
505
506 PyObject* CListValue::Pyfrom_id(PyObject* self, PyObject* value)
507 {
508 #if SIZEOF_VOID_P <= SIZEOF_LONG
509 #define BGE_ID_TYPE unsigned long
510         BGE_ID_TYPE id= PyLong_AsUnsignedLong(value);
511 #else
512 #define BGE_ID_TYPE unsigned long long
513         BGE_ID_TYPE id= PyLong_FromUnsignedLongLong(value);
514 #endif
515         
516         if (id==-1 && PyErr_Occurred())
517                 return NULL;
518
519         int numelem = GetCount();
520         for (int i=0;i<numelem;i++)
521         {
522                 if (reinterpret_cast<BGE_ID_TYPE>(static_cast<PyObject*>(m_pValueArray[i])) == id)
523                         return GetValue(i);
524         
525         }
526         PyErr_SetString(PyExc_IndexError, "from_id(#), id not found in CValueList");
527         return NULL;    
528
529 }
530
531 #undef BGE_ID_TYPE
532
533
534 /* --------------------------------------------------------------------- 
535  * Some stuff taken from the header
536  * --------------------------------------------------------------------- */
537 CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val) 
538 {
539         //assert(false); // todo: implement me!
540         fprintf(stderr, "CValueList::Calc not yet implimented\n");
541         return NULL;
542 }
543
544
545
546 CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype,
547                                                           VALUE_OPERATOR op, 
548                                                           CValue* val) 
549 {
550         //assert(false); // todo: implement me!
551         fprintf(stderr, "CValueList::CalcFinal not yet implimented\n");
552         return NULL;
553 }
554
555
556
557 void CListValue::Add(CValue* value)
558 {
559         m_pValueArray.push_back(value);
560 }
561
562
563
564 double CListValue::GetNumber()
565 {
566         return -1;
567 }
568
569
570
571 void CListValue::SetModified(bool bModified)
572 {       
573         CValue::SetModified(bModified);
574         int numels = GetCount();
575
576         for (int i=0;i<numels;i++)
577                 GetValue(i)->SetModified(bModified);
578 }
579
580
581
582 bool CListValue::IsModified()
583 {
584         bool bmod = CValue::IsModified(); //normal own flag
585         int numels = GetCount();
586
587         for (int i=0;i<numels;i++)
588                 bmod = bmod || GetValue(i)->IsModified();
589
590         return bmod;
591 }