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