|
dvander@60
|
1 |
/* |
|
dvander@60
|
2 |
* Copyright (C) 2004-2012 David Anderson |
|
dvander@60
|
3 |
* |
|
dvander@60
|
4 |
* This file is part of SourcePawn. |
|
dvander@60
|
5 |
* |
|
dvander@60
|
6 |
* SourcePawn is free software: you can redistribute it and/or modify it under |
|
dvander@60
|
7 |
* the terms of the GNU General Public License as published by the Free |
|
dvander@60
|
8 |
* Software Foundation, either version 3 of the License, or (at your option) |
|
dvander@60
|
9 |
* any later version. |
|
dvander@60
|
10 |
* |
|
dvander@60
|
11 |
* SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY |
|
dvander@60
|
12 |
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
dvander@60
|
13 |
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
|
dvander@60
|
14 |
* |
|
dvander@60
|
15 |
* You should have received a copy of the GNU General Public License along with |
|
dvander@60
|
16 |
* SourcePawn. If not, see http://www.gnu.org/licenses/. |
|
dvander@60
|
17 |
*/ |
|
dvander@60
|
18 |
#ifndef _include_sourcepawn3_api_h_ |
|
dvander@60
|
19 |
#define _include_sourcepawn3_api_h_ |
|
dvander@60
|
20 |
|
|
dvander@65
|
21 |
#include <assert.h> |
|
dvander@60
|
22 |
#include <stddef.h> |
|
dvander@64
|
23 |
#include "../include/keima_util.h" |
|
dvander@60
|
24 |
|
|
dvander@60
|
25 |
namespace ke { |
|
dvander@60
|
26 |
|
|
dvander@60
|
27 |
class Zone; |
|
dvander@60
|
28 |
class Object; |
|
dvander@60
|
29 |
class HandleScope; |
|
dvander@60
|
30 |
class HeapRoot; |
|
dvander@60
|
31 |
|
|
dvander@60
|
32 |
} |
|
dvander@60
|
33 |
|
|
dvander@60
|
34 |
namespace Ke { |
|
dvander@60
|
35 |
|
|
dvander@64
|
36 |
class Function; |
|
dvander@64
|
37 |
|
|
dvander@60
|
38 |
/* |
|
dvander@60
|
39 |
* A Handle is a safe pointer that holds an object reference, such that it |
|
dvander@60
|
40 |
* can be scanned and potentially moved by the garbage collector. |
|
dvander@60
|
41 |
*/ |
|
dvander@60
|
42 |
template <typename T> |
|
dvander@60
|
43 |
class Handle |
|
dvander@60
|
44 |
{ |
|
dvander@60
|
45 |
protected: |
|
dvander@60
|
46 |
template <typename S> void typeCheck() { |
|
dvander@60
|
47 |
while (false) { |
|
dvander@60
|
48 |
T *v1 = NULL; |
|
dvander@60
|
49 |
S *v2 = NULL; |
|
dvander@60
|
50 |
v1 = v2; |
|
dvander@60
|
51 |
(void)v1; |
|
dvander@60
|
52 |
} |
|
dvander@60
|
53 |
} |
|
dvander@60
|
54 |
|
|
dvander@60
|
55 |
public: |
|
dvander@60
|
56 |
Handle() |
|
dvander@60
|
57 |
: obj_(NULL) |
|
dvander@60
|
58 |
{ |
|
dvander@60
|
59 |
} |
|
dvander@60
|
60 |
|
|
dvander@60
|
61 |
template <typename S> Handle(Handle<S> other) |
|
dvander@60
|
62 |
: obj_(reinterpret_cast<S *>(*other)) |
|
dvander@60
|
63 |
{ |
|
dvander@60
|
64 |
typeCheck<S>(); |
|
dvander@60
|
65 |
} |
|
dvander@60
|
66 |
|
|
dvander@60
|
67 |
explicit Handle(T *obj) |
|
dvander@60
|
68 |
: obj_(obj) |
|
dvander@60
|
69 |
{ |
|
dvander@60
|
70 |
} |
|
dvander@60
|
71 |
|
|
dvander@60
|
72 |
T *operator ->() const { |
|
dvander@60
|
73 |
return obj_; |
|
dvander@60
|
74 |
} |
|
dvander@60
|
75 |
T *operator *() const { |
|
dvander@60
|
76 |
return obj_; |
|
dvander@60
|
77 |
} |
|
dvander@60
|
78 |
operator bool () const { |
|
dvander@60
|
79 |
return !!obj_; |
|
dvander@60
|
80 |
} |
|
dvander@60
|
81 |
|
|
dvander@65
|
82 |
protected: |
|
dvander@60
|
83 |
T *obj_; |
|
dvander@60
|
84 |
}; |
|
dvander@60
|
85 |
|
|
dvander@60
|
86 |
/* |
|
dvander@60
|
87 |
* A local variable that roots an object. Locals are owned by the nearest |
|
dvander@60
|
88 |
* HandleScope, and as soon as that HandleScope dies, all its Locals are |
|
dvander@60
|
89 |
* no longer available. |
|
dvander@60
|
90 |
*/ |
|
dvander@60
|
91 |
template <typename T> |
|
dvander@60
|
92 |
class Local : public Handle<T> |
|
dvander@60
|
93 |
{ |
|
dvander@60
|
94 |
public: |
|
dvander@60
|
95 |
Local() |
|
dvander@60
|
96 |
: Handle<T>() |
|
dvander@60
|
97 |
{ |
|
dvander@60
|
98 |
} |
|
dvander@60
|
99 |
|
|
dvander@60
|
100 |
template <typename S> Local(Local<S> other) |
|
dvander@60
|
101 |
: Handle<T>(reinterpret_cast<T *>(*other)) |
|
dvander@60
|
102 |
{ |
|
dvander@60
|
103 |
typeCheck<S>(); |
|
dvander@60
|
104 |
} |
|
dvander@60
|
105 |
|
|
dvander@60
|
106 |
template <typename S> Local(S *other) |
|
dvander@60
|
107 |
: Handle<T>(other) |
|
dvander@60
|
108 |
{ |
|
dvander@60
|
109 |
} |
|
dvander@60
|
110 |
}; |
|
dvander@60
|
111 |
|
|
dvander@60
|
112 |
/* |
|
dvander@60
|
113 |
* A non-local variable that outlives HandleScopes. A Root is reference- |
|
dvander@60
|
114 |
* counted. When its reference count reaches 0, the Root is removed. |
|
dvander@60
|
115 |
*/ |
|
dvander@60
|
116 |
template <typename T> |
|
dvander@60
|
117 |
class Root : public Handle<T> |
|
dvander@60
|
118 |
{ |
|
dvander@60
|
119 |
public: |
|
dvander@65
|
120 |
Root<T>() |
|
dvander@60
|
121 |
: Handle<T>() |
|
dvander@60
|
122 |
{ |
|
dvander@60
|
123 |
} |
|
dvander@60
|
124 |
|
|
dvander@65
|
125 |
Root<T>(const Root<T> &other) |
|
dvander@60
|
126 |
: Handle<T>(reinterpret_cast<T *>(*other)) |
|
dvander@60
|
127 |
{ |
|
dvander@60
|
128 |
incref(); |
|
dvander@60
|
129 |
} |
|
dvander@60
|
130 |
|
|
dvander@61
|
131 |
explicit Root(ke::HeapRoot *obj) |
|
dvander@60
|
132 |
: Handle<T>(reinterpret_cast<T *>(obj)) |
|
dvander@60
|
133 |
{ |
|
dvander@65
|
134 |
incref(); |
|
dvander@60
|
135 |
} |
|
dvander@60
|
136 |
|
|
dvander@61
|
137 |
static inline Root<T> New(Handle<T> other); |
|
dvander@60
|
138 |
|
|
dvander@60
|
139 |
~Root() { |
|
dvander@60
|
140 |
decref(); |
|
dvander@60
|
141 |
} |
|
dvander@60
|
142 |
|
|
dvander@65
|
143 |
Root<T> &operator =(const Root<T> &other) { |
|
dvander@60
|
144 |
decref(); |
|
dvander@65
|
145 |
obj_ = other.obj_; |
|
dvander@65
|
146 |
incref(); |
|
dvander@60
|
147 |
return *this; |
|
dvander@60
|
148 |
} |
|
dvander@60
|
149 |
|
|
dvander@60
|
150 |
private: |
|
dvander@60
|
151 |
void incref(); |
|
dvander@60
|
152 |
void decref(); |
|
dvander@60
|
153 |
}; |
|
dvander@60
|
154 |
|
|
dvander@60
|
155 |
/* |
|
dvander@60
|
156 |
* A HandleScope is where Local roots are allcoated. When the HandleScope |
|
dvander@60
|
157 |
* is destroyed, all Handles created under it are also destroyed. HandleScopes |
|
dvander@60
|
158 |
* may only be allocated on the stack, in LIFO order. |
|
dvander@60
|
159 |
*/ |
|
dvander@60
|
160 |
class HandleScope |
|
dvander@60
|
161 |
{ |
|
dvander@60
|
162 |
protected: |
|
dvander@60
|
163 |
ke::Zone *zone_; |
|
dvander@60
|
164 |
ke::Object **position_; |
|
dvander@60
|
165 |
HandleScope *prev_; |
|
dvander@60
|
166 |
|
|
dvander@60
|
167 |
HandleScope(ke::Zone *zone, ke::Object **position, HandleScope *prev) |
|
dvander@60
|
168 |
: zone_(zone), |
|
dvander@60
|
169 |
position_(position), |
|
dvander@60
|
170 |
prev_(prev) |
|
dvander@60
|
171 |
{ |
|
dvander@60
|
172 |
} |
|
dvander@60
|
173 |
|
|
dvander@60
|
174 |
public: |
|
dvander@60
|
175 |
HandleScope(); |
|
dvander@60
|
176 |
~HandleScope(); |
|
dvander@60
|
177 |
|
|
dvander@60
|
178 |
static ke::Object **CreateHandle(ke::Object *obj); |
|
dvander@60
|
179 |
|
|
dvander@60
|
180 |
private: |
|
dvander@60
|
181 |
// Disallow silly stuff. |
|
dvander@60
|
182 |
HandleScope(const HandleScope &); |
|
dvander@60
|
183 |
void operator =(const HandleScope &); |
|
dvander@60
|
184 |
void *operator new (size_t size); |
|
dvander@60
|
185 |
void operator delete(void *, size_t); |
|
dvander@60
|
186 |
}; |
|
dvander@60
|
187 |
|
|
dvander@65
|
188 |
class Parameter; |
|
dvander@65
|
189 |
|
|
dvander@64
|
190 |
// A string is an immutable UTF8 buffer. |
|
dvander@64
|
191 |
class KE_EXPORT String |
|
dvander@64
|
192 |
{ |
|
dvander@64
|
193 |
public: |
|
dvander@64
|
194 |
// Returns the length of the string, in bytes. |
|
dvander@64
|
195 |
unsigned length(); |
|
dvander@64
|
196 |
|
|
dvander@64
|
197 |
// Returns the character buffer of the string, or NULL on failure. If the |
|
dvander@64
|
198 |
// string is interned, chars() is guaranteed to succeed. |
|
dvander@64
|
199 |
const char *chars(); |
|
dvander@64
|
200 |
}; |
|
dvander@64
|
201 |
|
|
dvander@64
|
202 |
// A function is an executable unit of code. |
|
dvander@64
|
203 |
class KE_EXPORT Function |
|
dvander@64
|
204 |
{ |
|
dvander@64
|
205 |
public: |
|
dvander@64
|
206 |
// Returns the name of a function, which may be NULL. If not NULL, the |
|
dvander@68
|
207 |
// string is guaranteed to be interned. |
|
dvander@64
|
208 |
Local<String> name(); |
|
dvander@64
|
209 |
}; |
|
dvander@64
|
210 |
|
|
dvander@68
|
211 |
// A native is an ISourcePawnEngine-compatible function provided by C++. |
|
dvander@68
|
212 |
class KE_EXPORT Native |
|
dvander@68
|
213 |
{ |
|
dvander@68
|
214 |
public: |
|
dvander@68
|
215 |
// Returns the name of a native, which is never NULL. The string is |
|
dvander@68
|
216 |
// guaranteed to be interned. |
|
dvander@68
|
217 |
Local<String> name(); |
|
dvander@68
|
218 |
|
|
dvander@68
|
219 |
// Returns the function pointer of the native. |
|
dvander@68
|
220 |
void *function(); |
|
dvander@68
|
221 |
|
|
dvander@68
|
222 |
// Sets the function pointer of the native. |
|
dvander@68
|
223 |
void bind(void *function); |
|
dvander@68
|
224 |
}; |
|
dvander@68
|
225 |
|
|
dvander@62
|
226 |
// A module represents a single compiled file, and contains functions and |
|
dvander@62
|
227 |
// global variables for that file (as well as exported types). |
|
dvander@64
|
228 |
class KE_EXPORT Module |
|
dvander@62
|
229 |
{ |
|
dvander@62
|
230 |
public: |
|
dvander@64
|
231 |
// Returns publics that are based on forwards. |
|
dvander@64
|
232 |
unsigned numPublics(); |
|
dvander@64
|
233 |
Local<Function> getPublic(unsigned index); |
|
dvander@68
|
234 |
|
|
dvander@68
|
235 |
// Returns natives. |
|
dvander@68
|
236 |
unsigned numNatives(); |
|
dvander@68
|
237 |
Local<Native> getNative(unsigned index); |
|
dvander@68
|
238 |
|
|
dvander@68
|
239 |
// Sets the native identity pointer, which is passed as the first argument |
|
dvander@68
|
240 |
// to natives. |
|
dvander@68
|
241 |
void setNativeIdentity(void *ptr); |
|
dvander@62
|
242 |
}; |
|
dvander@62
|
243 |
|
|
dvander@62
|
244 |
class Keima |
|
dvander@62
|
245 |
{ |
|
dvander@62
|
246 |
public: |
|
dvander@62
|
247 |
/* |
|
dvander@62
|
248 |
* Initializes the Keima engine. This must be called exactly once before any |
|
dvander@62
|
249 |
* other Keima functions are called. After this, it is safe to use Keima |
|
dvander@62
|
250 |
* on the calling thread. |
|
dvander@62
|
251 |
*/ |
|
dvander@62
|
252 |
static bool Initialize(); |
|
dvander@60
|
253 |
|
|
dvander@62
|
254 |
/* |
|
dvander@62
|
255 |
* Shuts down the Keima engine and frees data structures on all threads. |
|
dvander@62
|
256 |
*/ |
|
dvander@62
|
257 |
static void Shutdown(); |
|
dvander@60
|
258 |
|
|
dvander@62
|
259 |
/* |
|
dvander@62
|
260 |
* Searches the call stack and returns true if the given module has any |
|
dvander@62
|
261 |
* active code running. This is an O(n) algorithm. |
|
dvander@62
|
262 |
*/ |
|
dvander@62
|
263 |
static bool IsInCallStack(Handle<Module> module); |
|
dvander@62
|
264 |
|
|
dvander@62
|
265 |
/* |
|
dvander@62
|
266 |
* Reclaim as much memory as possible. This pauses the calling thread |
|
dvander@62
|
267 |
* until garbage collection completes. |
|
dvander@62
|
268 |
*/ |
|
dvander@62
|
269 |
static void CollectGarbage(); |
|
dvander@64
|
270 |
|
|
dvander@64
|
271 |
/* |
|
dvander@64
|
272 |
* Clear any pending exception. |
|
dvander@64
|
273 |
*/ |
|
dvander@64
|
274 |
static void ClearPendingException(); |
|
dvander@65
|
275 |
|
|
dvander@65
|
276 |
/* |
|
dvander@65
|
277 |
* Type checks a function against given parameters. |
|
dvander@65
|
278 |
*/ |
|
dvander@65
|
279 |
static bool CheckInvokeTypes(Handle<Function> fun, const Parameter *params, unsigned nparams); |
|
dvander@65
|
280 |
|
|
dvander@65
|
281 |
/* |
|
dvander@65
|
282 |
* Executes a function with the given parameters. This interface is |
|
dvander@65
|
283 |
* intended for compatibility with SourceMod's ISourcePawnEngine2 and |
|
dvander@65
|
284 |
* should not be used otherwise, since it is intended to support only |
|
dvander@65
|
285 |
* a small subset of the core language. |
|
dvander@65
|
286 |
*/ |
|
dvander@65
|
287 |
static bool Invoke(Handle<Function> fun, const Parameter *params, unsigned nparams, int *result); |
|
dvander@62
|
288 |
}; |
|
dvander@60
|
289 |
|
|
dvander@60
|
290 |
/* |
|
dvander@64
|
291 |
* Suppresses exceptions. This is useful for calling API functions. When this |
|
dvander@64
|
292 |
* in scope, errors will be reported, but the exception will be cleared after. |
|
dvander@64
|
293 |
*/ |
|
dvander@64
|
294 |
class AutoClearExceptions |
|
dvander@64
|
295 |
{ |
|
dvander@64
|
296 |
public: |
|
dvander@64
|
297 |
~AutoClearExceptions() |
|
dvander@64
|
298 |
{ |
|
dvander@64
|
299 |
Keima::ClearPendingException(); |
|
dvander@64
|
300 |
} |
|
dvander@64
|
301 |
}; |
|
dvander@64
|
302 |
|
|
dvander@65
|
303 |
// Argument-passing interface for Invoke(). |
|
dvander@65
|
304 |
class Parameter |
|
dvander@65
|
305 |
{ |
|
dvander@65
|
306 |
public: |
|
dvander@65
|
307 |
enum Type { |
|
dvander@65
|
308 |
Int, |
|
dvander@65
|
309 |
Float, |
|
dvander@65
|
310 |
IntRef, |
|
dvander@65
|
311 |
FloatRef, |
|
dvander@65
|
312 |
Array, |
|
dvander@65
|
313 |
CharArray |
|
dvander@65
|
314 |
}; |
|
dvander@65
|
315 |
|
|
dvander@65
|
316 |
Parameter() |
|
dvander@65
|
317 |
{ |
|
dvander@65
|
318 |
} |
|
dvander@65
|
319 |
|
|
dvander@65
|
320 |
Parameter(int i) |
|
dvander@65
|
321 |
: type_(Int) |
|
dvander@65
|
322 |
{ |
|
dvander@65
|
323 |
u.i = i; |
|
dvander@65
|
324 |
} |
|
dvander@65
|
325 |
|
|
dvander@65
|
326 |
Parameter(int *i, bool writeback) |
|
dvander@65
|
327 |
: type_(IntRef), |
|
dvander@65
|
328 |
writeback_(writeback) |
|
dvander@65
|
329 |
{ |
|
dvander@65
|
330 |
u.ip = i; |
|
dvander@65
|
331 |
} |
|
dvander@65
|
332 |
|
|
dvander@65
|
333 |
Parameter(float f) |
|
dvander@65
|
334 |
: type_(Float) |
|
dvander@65
|
335 |
{ |
|
dvander@65
|
336 |
u.f = f; |
|
dvander@65
|
337 |
} |
|
dvander@65
|
338 |
|
|
dvander@65
|
339 |
Parameter(float *f, bool writeback) |
|
dvander@65
|
340 |
: type_(FloatRef), |
|
dvander@65
|
341 |
writeback_(writeback) |
|
dvander@65
|
342 |
{ |
|
dvander@65
|
343 |
u.fp = f; |
|
dvander@65
|
344 |
} |
|
dvander@65
|
345 |
|
|
dvander@65
|
346 |
Parameter(Type type, void *buffer, size_t length, bool writeback) |
|
dvander@65
|
347 |
: type_(type), |
|
dvander@65
|
348 |
writeback_(writeback), |
|
dvander@65
|
349 |
length_(length) |
|
dvander@65
|
350 |
{ |
|
dvander@65
|
351 |
assert(type == Array || type == CharArray); |
|
dvander@65
|
352 |
u.buffer = buffer; |
|
dvander@65
|
353 |
} |
|
dvander@65
|
354 |
|
|
dvander@65
|
355 |
Type type() const { |
|
dvander@65
|
356 |
return type_; |
|
dvander@65
|
357 |
} |
|
dvander@65
|
358 |
|
|
dvander@65
|
359 |
int i32() const { |
|
dvander@65
|
360 |
assert(type() == Int); |
|
dvander@65
|
361 |
return u.i; |
|
dvander@65
|
362 |
} |
|
dvander@65
|
363 |
float f() const { |
|
dvander@65
|
364 |
assert(type() == Float); |
|
dvander@65
|
365 |
return u.f; |
|
dvander@65
|
366 |
} |
|
dvander@65
|
367 |
int *i32p() const { |
|
dvander@65
|
368 |
assert(type() == IntRef); |
|
dvander@65
|
369 |
return u.ip; |
|
dvander@65
|
370 |
} |
|
dvander@65
|
371 |
float *fp() const { |
|
dvander@65
|
372 |
assert(type() == FloatRef); |
|
dvander@65
|
373 |
return u.fp; |
|
dvander@65
|
374 |
} |
|
dvander@65
|
375 |
bool writeback() const { |
|
dvander@65
|
376 |
assert(type() >= IntRef && type() <= CharArray); |
|
dvander@65
|
377 |
return writeback_; |
|
dvander@65
|
378 |
} |
|
dvander@65
|
379 |
size_t length() const { |
|
dvander@65
|
380 |
return length_; |
|
dvander@65
|
381 |
} |
|
dvander@65
|
382 |
void *buffer() const { |
|
dvander@65
|
383 |
assert(type() == Array || type() == CharArray); |
|
dvander@65
|
384 |
return u.buffer; |
|
dvander@65
|
385 |
} |
|
dvander@65
|
386 |
|
|
dvander@65
|
387 |
private: |
|
dvander@65
|
388 |
Type type_; |
|
dvander@65
|
389 |
bool writeback_; |
|
dvander@65
|
390 |
size_t length_; |
|
dvander@65
|
391 |
|
|
dvander@65
|
392 |
union { |
|
dvander@65
|
393 |
int i; |
|
dvander@65
|
394 |
float f; |
|
dvander@65
|
395 |
int *ip; |
|
dvander@65
|
396 |
float *fp; |
|
dvander@65
|
397 |
void *buffer; |
|
dvander@65
|
398 |
} u; |
|
dvander@65
|
399 |
}; |
|
dvander@64
|
400 |
|
|
dvander@64
|
401 |
/* |
|
dvander@60
|
402 |
* Compiles a file and returns a Module. |
|
dvander@60
|
403 |
*/ |
|
dvander@60
|
404 |
extern Local<Module> Compile(const char *path); |
|
dvander@60
|
405 |
|
|
dvander@61
|
406 |
class Internals |
|
dvander@61
|
407 |
{ |
|
dvander@61
|
408 |
template <typename T> friend class Root; |
|
dvander@61
|
409 |
|
|
dvander@61
|
410 |
private: |
|
dvander@61
|
411 |
static ke::HeapRoot *NewHeapRoot(ke::Object **objp); |
|
dvander@61
|
412 |
static void IncRef(ke::HeapRoot *root); |
|
dvander@61
|
413 |
static void DecRef(ke::HeapRoot *root); |
|
dvander@61
|
414 |
}; |
|
dvander@61
|
415 |
|
|
dvander@61
|
416 |
template <typename T> Root<T> |
|
dvander@61
|
417 |
Root<T>::New(Handle<T> other) |
|
dvander@61
|
418 |
{ |
|
dvander@61
|
419 |
if (!other) |
|
dvander@65
|
420 |
return Root<T>(); |
|
dvander@61
|
421 |
ke::Object **ptr = reinterpret_cast<ke::Object **>(*other); |
|
dvander@61
|
422 |
return Root<T>(Internals::NewHeapRoot(ptr)); |
|
dvander@61
|
423 |
} |
|
dvander@61
|
424 |
|
|
dvander@61
|
425 |
template <typename T> void |
|
dvander@61
|
426 |
Root<T>::incref() |
|
dvander@61
|
427 |
{ |
|
dvander@61
|
428 |
if (!*this) |
|
dvander@61
|
429 |
return; |
|
dvander@61
|
430 |
ke::HeapRoot *ptr = reinterpret_cast<ke::HeapRoot *>(**this); |
|
dvander@61
|
431 |
Internals::IncRef(ptr); |
|
dvander@61
|
432 |
} |
|
dvander@61
|
433 |
|
|
dvander@61
|
434 |
template <typename T> void |
|
dvander@61
|
435 |
Root<T>::decref() |
|
dvander@61
|
436 |
{ |
|
dvander@61
|
437 |
if (!*this) |
|
dvander@61
|
438 |
return; |
|
dvander@61
|
439 |
ke::HeapRoot *ptr = reinterpret_cast<ke::HeapRoot *>(**this); |
|
dvander@61
|
440 |
Internals::DecRef(ptr); |
|
dvander@61
|
441 |
} |
|
dvander@61
|
442 |
|
|
dvander@60
|
443 |
} |
|
dvander@60
|
444 |
|
|
dvander@60
|
445 |
#endif // _include_sourcepawn3_api_h_ |