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