11d40950aedb9981577e503c8cddf07f2795b3c4
[supertux.git] / src / squirrel / squirrel / sqclass.cpp
1 /*
2         see copyright notice in squirrel.h
3 */
4 #include "sqpcheader.h"
5 #include "sqvm.h"
6 #include "sqtable.h"
7 #include "sqclass.h"
8 #include "sqclosure.h"
9
10 SQClass::SQClass(SQSharedState *ss,SQClass *base)
11 {
12         _uiRef=0;
13         _base = base;
14         _typetag = 0;
15         _metamethods.resize(MT_LAST); //size it to max size
16         if(_base) {
17                 _defaultvalues.copy(base->_defaultvalues);
18                 _methods.copy(base->_methods);
19                 _metamethods.copy(base->_metamethods);
20                 __ObjAddRef(_base);
21         }
22         _members = base?base->_members->Clone() : SQTable::Create(ss,0);
23         __ObjAddRef(_members);
24         _locked = false;
25         INIT_CHAIN();
26         ADD_TO_CHAIN(&_sharedstate->_gc_chain, this);
27 }
28
29 void SQClass::Finalize() { 
30         _attributes = _null_;
31         _defaultvalues.resize(0);
32         _methods.resize(0);
33         _metamethods.resize(0);
34         __ObjRelease(_members);
35         if(_base) {
36                 __ObjRelease(_base);
37         }
38 }
39
40 SQClass::~SQClass()
41 {
42         REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);
43         Finalize();
44 }
45
46 bool SQClass::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)
47 {
48         SQObjectPtr temp;
49         if(_locked) 
50                 return false; //the slot already exists
51         if(_members->Get(key,temp) && type(temp) == OT_INTEGER) //overrides the default value
52         {
53                 _defaultvalues[_integer(temp)].val = val;
54                 return true;
55         }
56         if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) {
57                 SQInteger mmidx;
58                 if((mmidx = _sharedstate->GetMetaMethodIdxByName(key)) != -1) {
59                         _metamethods[mmidx] = val;
60                 } 
61                 else {
62                         if(type(temp) == OT_NULL) {
63                                 SQClassMemeber m;
64                                 m.val = val;
65                                 _members->NewSlot(key,SQObjectPtr((SQUserPointer)_methods.size()));
66                                 _methods.push_back(m);
67                         }
68                         else {
69                                 _methods[(int)_userpointer(temp)].val = val;
70                         }
71                 }
72                 return true;
73         }
74         SQClassMemeber m;
75         m.val = val;
76         _members->NewSlot(key,SQObjectPtr((SQInteger)_defaultvalues.size()));
77         _defaultvalues.push_back(m);
78         return true;
79 }
80
81 SQInstance *SQClass::CreateInstance()
82 {
83         if(!_locked) Lock();
84         return SQInstance::Create(_opt_ss(this),this);
85 }
86
87 int SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
88 {
89         SQObjectPtr oval;
90         int idx = _members->Next(refpos,outkey,oval);
91         if(idx != -1) {
92                 if(type(oval) != OT_INTEGER) {
93                         outval = _methods[(int)_userpointer(oval)].val;
94                 }
95                 else {
96                         outval = _defaultvalues[_integer(oval)].val;
97                 }
98         }
99         return idx;
100 }
101
102 bool SQClass::SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val)
103 {
104         SQObjectPtr idx;
105         if(_members->Get(key,idx)) {
106                 if(type(idx) == OT_INTEGER)
107                         _defaultvalues[_integer(idx)].attrs = val;
108                 else
109                         _methods[(int)_userpointer(idx)].attrs = val;
110                 return true;
111         }
112         return false;
113 }
114
115 bool SQClass::GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval)
116 {
117         SQObjectPtr idx;
118         if(_members->Get(key,idx)) {
119                 outval = (type(idx) == OT_INTEGER?_defaultvalues[_integer(idx)].attrs:_methods[(int)_userpointer(idx)].attrs);
120                 return true;
121         }
122         return false;
123 }
124
125 ///////////////////////////////////////////////////////////////////////
126 void SQInstance::Init(SQSharedState *ss)
127 {
128         _uiRef = 0;
129         _userpointer = NULL;
130         _hook = NULL;
131         __ObjAddRef(_class);
132         _delegate = _class->_members;
133         INIT_CHAIN();
134         ADD_TO_CHAIN(&_sharedstate->_gc_chain, this);
135 }
136
137 SQInstance::SQInstance(SQSharedState *ss, SQClass *c)
138 {
139         _class = c;
140         _values.resize(_class->_defaultvalues.size());
141         for(unsigned int i = 0; i < _class->_defaultvalues.size(); i++) {
142                 _values[i] = _class->_defaultvalues[i].val;
143         }
144         Init(ss);
145 }
146
147 SQInstance::SQInstance(SQSharedState *ss, SQInstance *i)
148 {
149         _class = i->_class;
150         _values.copy(i->_values);
151         Init(ss);
152 }
153
154 void SQInstance::Finalize() 
155 {
156         __ObjRelease(_class);
157         _values.resize(0);
158 }
159
160 SQInstance::~SQInstance()
161 {
162         REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);
163         Finalize();
164 }
165
166 bool SQInstance::GetMetaMethod(SQMetaMethod mm,SQObjectPtr &res)
167 {
168         if(type(_class->_metamethods[mm]) != OT_NULL) {
169                 res = _class->_metamethods[mm];
170                 return true;
171         }
172         return false;
173 }
174
175 bool SQInstance::InstanceOf(SQClass *trg)
176 {
177         SQClass *parent = _class;
178         while(parent != NULL) {
179                 if(parent == trg)
180                         return true;
181                 parent = parent->_base;
182         }
183         return false;
184 }