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