sqrat  0.9
sqrat
 All Classes Functions Variables Enumerations Enumerator Pages
sqratClass.h
1 //
2 // SqratClass: Class Binding
3 //
4 
5 //
6 // Copyright (c) 2009 Brandon Jones
7 //
8 // This software is provided 'as-is', without any express or implied
9 // warranty. In no event will the authors be held liable for any damages
10 // arising from the use of this software.
11 //
12 // Permission is granted to anyone to use this software for any purpose,
13 // including commercial applications, and to alter it and redistribute it
14 // freely, subject to the following restrictions:
15 //
16 // 1. The origin of this software must not be misrepresented; you must not
17 // claim that you wrote the original software. If you use this software
18 // in a product, an acknowledgment in the product documentation would be
19 // appreciated but is not required.
20 //
21 // 2. Altered source versions must be plainly marked as such, and must not be
22 // misrepresented as being the original software.
23 //
24 // 3. This notice may not be removed or altered from any source
25 // distribution.
26 //
27 
28 #if !defined(_SCRAT_CLASS_H_)
29 #define _SCRAT_CLASS_H_
30 
31 #include <typeinfo>
32 #include <squirrel.h>
33 #include <string.h>
34 
35 #include "sqratObject.h"
36 #include "sqratClassType.h"
37 #include "sqratMemberMethods.h"
38 #include "sqratAllocator.h"
39 
40 namespace Sqrat
41 {
42 
55 template<class C, class A = DefaultAllocator<C> >
56 class Class : public Object
57 {
58  static SQInteger cleanup_hook(SQUserPointer p, SQInteger /*size*/)
59  {
60  HSQUIRRELVM v = *(HSQUIRRELVM *) p;
61  ClassTypeData<C, void>* ptr = static_cast<ClassTypeData<C, void>*>(ClassType<C>::getClassTypeData(v));
62  delete ptr;
63  ClassType<C>::deleteClassTypeData(v);
64  return 1;
65  }
66 public:
86  Class(HSQUIRRELVM v = DefaultVM::Get(), const string& className = string() , bool createClass = true) : Object(v, false) {
87  if(createClass && !ClassType<C>::hasClassTypeData(v)) {
88  ClassType<C>::getClassTypeData(v) = new ClassTypeData<C, void>;
89  HSQOBJECT& classObj = ClassType<C>::ClassObject(v);
90  sq_resetobject(&classObj);
91 
92  sq_newclass(vm, false);
93  sq_getstackobj(vm, -1, &classObj);
94  sq_addref(vm, &classObj); // must addref before the pop!
95  sq_pop(vm, 1);
96  if (className.empty())
97 #ifdef SQUNICODE
98  InitClass(string_to_wstring(typeid(*this).name()));
99 #else
100  InitClass(typeid(*this).name());
101 #endif
102  else InitClass(className);
103 
104  // install cleanup hook
105  HSQUIRRELVM *p = (HSQUIRRELVM *) sq_newuserdata(v, sizeof(v));
106  *p = v;
107 
108  sq_setreleasehook(v, -1, cleanup_hook);
109  // finish install cleanup hook
110  }
111  }
112 
119  virtual HSQOBJECT GetObject() const {
120  return ClassType<C>::ClassObject(vm);
121  }
122 
129  virtual HSQOBJECT& GetObject() {
130  return ClassType<C>::ClassObject(vm);
131  }
132 
133 public:
148  template<class V>
149  Class& SetStaticValue(const SQChar* name, const V& val) {
150  BindValue<V>(name, val, true);
151  return *this;
152  }
153 
165  template<class V>
166  Class& SetValue(const SQChar* name, const V& val) {
167  BindValue<V>(name, val, false);
168  return *this;
169  }
170 
182  template<class V>
183  Class& Var(const SQChar* name, V C::* var) {
184  // Add the getter
185  BindAccessor(name, &var, sizeof(var), &sqDefaultGet<C, V>, ClassType<C>::GetTable(vm));
186 
187  // Add the setter
188  BindAccessor(name, &var, sizeof(var), &sqDefaultSet<C, V>, ClassType<C>::SetTable(vm));
189 
190  return *this;
191  }
192 
204  template<class V>
205  Class& StaticVar(const SQChar* name, V* var) {
206  // Add the getter
207  BindAccessor(name, &var, sizeof(var), &sqStaticGet<C, V>, ClassType<C>::GetTable(vm));
208 
209  // Add the setter
210  BindAccessor(name, &var, sizeof(var), &sqStaticSet<C, V>, ClassType<C>::SetTable(vm));
211 
212  return *this;
213  }
214 
231  template<class F1, class F2>
232  Class& Prop(const SQChar* name, F1 getMethod, F2 setMethod) {
233  if(getMethod != NULL) {
234  // Add the getter
235  BindAccessor(name, &getMethod, sizeof(getMethod), SqMemberOverloadedFunc(getMethod), ClassType<C>::GetTable(vm));
236  }
237 
238  if(setMethod != NULL) {
239  // Add the setter
240  BindAccessor(name, &setMethod, sizeof(setMethod), SqMemberOverloadedFunc(setMethod), ClassType<C>::SetTable(vm));
241  }
242 
243  return *this;
244  }
245 
262  template<class F1, class F2>
263  Class& GlobalProp(const SQChar* name, F1 getMethod, F2 setMethod) {
264  if(getMethod != NULL) {
265  // Add the getter
266  BindAccessor(name, &getMethod, sizeof(getMethod), SqMemberGlobalOverloadedFunc(getMethod), ClassType<C>::GetTable(vm));
267  }
268 
269  if(setMethod != NULL) {
270  // Add the setter
271  BindAccessor(name, &setMethod, sizeof(setMethod), SqMemberGlobalOverloadedFunc(setMethod), ClassType<C>::SetTable(vm));
272  }
273 
274  return *this;
275  }
276 
291  template<class F>
292  Class& Prop(const SQChar* name, F getMethod) {
293  // Add the getter
294  BindAccessor(name, &getMethod, sizeof(getMethod), SqMemberOverloadedFunc(getMethod), ClassType<C>::GetTable(vm));
295 
296  return *this;
297  }
298 
313  template<class F>
314  Class& GlobalProp(const SQChar* name, F getMethod) {
315  // Add the getter
316  BindAccessor(name, &getMethod, sizeof(getMethod), SqMemberGlobalOverloadedFunc(getMethod), ClassType<C>::GetTable(vm));
317 
318  return *this;
319  }
320 
332  template<class F>
333  Class& Func(const SQChar* name, F method) {
334  BindFunc(name, &method, sizeof(method), SqMemberFunc(method));
335  return *this;
336  }
337 
353  template<class F>
354  Class& Overload(const SQChar* name, F method) {
355  BindOverload(name, &method, sizeof(method), SqMemberOverloadedFunc(method), SqOverloadFunc(method), SqGetArgCount(method));
356  return *this;
357  }
358 
370  template<class F>
371  Class& GlobalFunc(const SQChar* name, F method) {
372  BindFunc(name, &method, sizeof(method), SqMemberGlobalFunc(method));
373  return *this;
374  }
375 
387  template<class F>
388  Class& StaticFunc(const SQChar* name, F method) {
389  BindFunc(name, &method, sizeof(method), SqGlobalFunc(method));
390  return *this;
391  }
392 
408  template<class F>
409  Class& GlobalOverload(const SQChar* name, F method) {
410  BindOverload(name, &method, sizeof(method), SqMemberGlobalOverloadedFunc(method), SqOverloadFunc(method), SqGetArgCount(method) - 1);
411  return *this;
412  }
413 
429  template<class F>
430  Class& StaticOverload(const SQChar* name, F method) {
431  BindOverload(name, &method, sizeof(method), SqGlobalOverloadedFunc(method), SqOverloadFunc(method), SqGetArgCount(method));
432  return *this;
433  }
434 
448  Class& SquirrelFunc(const SQChar* name, SQFUNCTION func) {
449  sq_pushobject(vm, ClassType<C>::ClassObject(vm));
450  sq_pushstring(vm, name, -1);
451  sq_newclosure(vm, func, 0);
452  sq_newslot(vm, -3, false);
453  sq_pop(vm, 1); // pop table
454 
455  return *this;
456  }
457 
466  Function GetFunction(const SQChar* name) {
467  HSQOBJECT funcObj;
468  sq_pushobject(vm, ClassType<C>::ClassObject(vm));
469  sq_pushstring(vm, name, -1);
470 #if !defined (SCRAT_NO_ERROR_CHECKING)
471  if(SQ_FAILED(sq_get(vm, -2))) {
472  sq_pop(vm, 1);
473  return Function();
474  }
475  SQObjectType value_type = sq_gettype(vm, -1);
476  if (value_type != OT_CLOSURE && value_type != OT_NATIVECLOSURE) {
477  sq_pop(vm, 2);
478  return Function();
479  }
480 #else
481  sq_get(vm, -2);
482 #endif
483  sq_getstackobj(vm, -1, &funcObj);
484  Function ret(vm, ClassType<C>::ClassObject(vm), funcObj); // must addref before the pop!
485  sq_pop(vm, 2);
486  return ret;
487  }
488 
489 protected:
490 
492 
493  static SQInteger ClassWeakref(HSQUIRRELVM vm) {
494  sq_weakref(vm, -1);
495  return 1;
496  }
497 
498  static SQInteger ClassTypeof(HSQUIRRELVM vm) {
499  sq_pushstring(vm, ClassType<C>::ClassName(vm).c_str(), -1);
500  return 1;
501  }
502 
503  // Initialize the required data structure for the class
504  void InitClass(const string& className) {
505  ClassType<C>::CopyFunc(vm) = &A::Copy;
506  ClassType<C>::ClassName(vm) = className;
507  ClassType<C>::BaseClass(vm) = NULL;
508 
509  // push the class
510  sq_pushobject(vm, ClassType<C>::ClassObject(vm));
511 
512  // set the typetag of the class
513  sq_settypetag(vm, -1, ClassType<C>::getClassTypeData(vm));
514 
515  // add the default constructor
516  sq_pushstring(vm,_SC("constructor"), -1);
517  sq_newclosure(vm, &A::New, 0);
518  sq_newslot(vm, -3, false);
519 
520  // add the set table (static)
521  HSQOBJECT& setTable = ClassType<C>::SetTable(vm);
522  sq_resetobject(&setTable);
523  sq_pushstring(vm,_SC("__setTable"), -1);
524  sq_newtable(vm);
525  sq_getstackobj(vm, -1, &setTable);
526  sq_addref(vm, &setTable);
527  sq_newslot(vm, -3, true);
528 
529  // add the get table (static)
530  HSQOBJECT& getTable = ClassType<C>::GetTable(vm);
531  sq_resetobject(&getTable);
532  sq_pushstring(vm,_SC("__getTable"), -1);
533  sq_newtable(vm);
534  sq_getstackobj(vm, -1, &getTable);
535  sq_addref(vm, &getTable);
536  sq_newslot(vm, -3, true);
537 
538  // override _set
539  sq_pushstring(vm, _SC("_set"), -1);
540  sq_pushobject(vm, setTable); // Push the set table as a free variable
541  sq_newclosure(vm, &sqVarSet, 1);
542  sq_newslot(vm, -3, false);
543 
544  // override _get
545  sq_pushstring(vm, _SC("_get"), -1);
546  sq_pushobject(vm, getTable); // Push the get table as a free variable
547  sq_newclosure(vm, &sqVarGet, 1);
548  sq_newslot(vm, -3, false);
549 
550  // add weakref (apparently not provided by default)
551  sq_pushstring(vm, _SC("weakref"), -1);
552  sq_newclosure(vm, &Class::ClassWeakref, 0);
553  sq_newslot(vm, -3, false);
554 
555  // add _typeof
556  sq_pushstring(vm, _SC("_typeof"), -1);
557  sq_newclosure(vm, &Class::ClassTypeof, 0);
558  sq_newslot(vm, -3, false);
559 
560  // pop the class
561  sq_pop(vm, 1);
562  }
563 
564  // Helper function used to bind getters and setters
565  inline void BindAccessor(const SQChar* name, void* var, size_t varSize, SQFUNCTION func, HSQOBJECT table) {
566  // Push the get or set table
567  sq_pushobject(vm, table);
568  sq_pushstring(vm, name, -1);
569 
570  // Push the variable offset as a free variable
571  SQUserPointer varPtr = sq_newuserdata(vm, static_cast<SQUnsignedInteger>(varSize));
572  memcpy(varPtr, var, varSize);
573 
574  // Create the accessor function
575  sq_newclosure(vm, func, 1);
576 
577  // Add the accessor to the table
578  sq_newslot(vm, -3, false);
579 
580  // Pop get/set table
581  sq_pop(vm, 1);
582  }
583 
584 
585  // constructor binding
586  Class& BindConstructor(SQFUNCTION method, SQInteger nParams, const SQChar *name = 0){
587  SQFUNCTION overload = SqOverloadFunc(method);
588  bool alternative_global = false;
589  if (name == 0)
590  name = _SC("constructor");
591  else alternative_global = true;
592  string overloadName = SqOverloadName::Get(name, nParams);
593 
594  if (!alternative_global )
595  {
596  // push the class
597  sq_pushobject(vm, ClassType<C>::ClassObject(vm));
598  }
599  else
600  {
601  // the containing environment is the root table??
602  sq_pushroottable(vm);
603  }
604 
605  // Bind overload handler
606  sq_pushstring(vm, name, -1);
607  sq_pushstring(vm, name, -1); // function name is passed as a free variable
608  sq_newclosure(vm, overload, 1);
609  sq_newslot(vm, -3, false);
610 
611  // Bind overloaded allocator function
612  sq_pushstring(vm, overloadName.c_str(), -1);
613  sq_newclosure(vm, method, 0);
614  sq_setparamscheck(vm,nParams + 1,NULL);
615  sq_newslot(vm, -3, false);
616  sq_pop(vm, 1);
617  return *this;
618  }
619 
620  void setDefaultCtor()
621  {
622  ClassTypeDataBase *type_data = ClassType<C>::getClassTypeData(vm);
623  if (type_data->ctorCalled == false)
624  {
625  Ctor(); // set up default constructor with the 'constructor' override
626  type_data->ctorCalled = true;
627  }
628  }
629 
631 
632 public:
641  Class& Ctor(const SQChar *name = 0) {
642  return BindConstructor(A::template iNew<0>, 0, name);
643  }
644 
655  template<class A1>
656  Class& Ctor(const SQChar *name = 0) {
657  setDefaultCtor();
658  return BindConstructor(A::template iNew<A1>,1, name);
659  }
660 
672  template<class A1,class A2>
673  Class& Ctor(const SQChar *name = 0) {
674  setDefaultCtor();
675  return BindConstructor(A::template iNew<A1,A2>,2, name);
676  }
677 
690  template<class A1,class A2,class A3>
691  Class& Ctor(const SQChar *name = 0) {
692  setDefaultCtor();
693  return BindConstructor(A::template iNew<A1,A2,A3>,3, name);
694  }
695 
709  template<class A1,class A2,class A3,class A4>
710  Class& Ctor(const SQChar *name = 0) {
711  setDefaultCtor();
712  return BindConstructor(A::template iNew<A1,A2,A3,A4>,4, name);
713  }
714 
729  template<class A1,class A2,class A3,class A4,class A5>
730  Class& Ctor(const SQChar *name = 0) {
731  setDefaultCtor();
732  return BindConstructor(A::template iNew<A1,A2,A3,A4,A5>,5, name);
733  }
734 
750  template<class A1,class A2,class A3,class A4,class A5,class A6>
751  Class& Ctor(const SQChar *name = 0) {
752  setDefaultCtor();
753  return BindConstructor(A::template iNew<A1,A2,A3,A4,A5,A6>,6, name);
754  }
755 
772  template<class A1,class A2,class A3,class A4,class A5,class A6,class A7>
773  Class& Ctor(const SQChar *name = 0) {
774  setDefaultCtor();
775  return BindConstructor(A::template iNew<A1,A2,A3,A4,A5,A6,A7>,7, name);
776  }
777 
795  template<class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8>
796  Class& Ctor(const SQChar *name = 0) {
797  setDefaultCtor();
798  return BindConstructor(A::template iNew<A1,A2,A3,A4,A5,A6,A7,A8>,8, name);
799  }
800 
819  template<class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8,class A9>
820  Class& Ctor(const SQChar *name = 0) {
821  setDefaultCtor();
822  return BindConstructor(A::template iNew<A1,A2,A3,A4,A5,A6,A7,A8,A9>,9, name);
823  }
824 };
825 
842 template<class C, class B, class A = DefaultAllocator<C> >
843 class DerivedClass : public Class<C, A>
844 {
845  static SQInteger cleanup_hook(SQUserPointer p, SQInteger /*size*/)
846  {
847  HSQUIRRELVM v = *(HSQUIRRELVM *) p;
848  ClassTypeData<C, B>* ptr = static_cast<ClassTypeData<C, B>*>(ClassType<C>::getClassTypeData(v));
849  delete ptr;
850  ClassType<C>::deleteClassTypeData(v);
851  return 1;
852  }
853 public:
872  DerivedClass(HSQUIRRELVM v = DefaultVM::Get(), const string& className = string()) : Class<C, A>(v, string(), false) {
873  if(!ClassType<C>::hasClassTypeData(v)) {
874  ClassType<C>::getClassTypeData(v) = new ClassTypeData<C, B>;
875  HSQOBJECT& classObj = ClassType<C>::ClassObject(v);
876  sq_resetobject(&classObj);
877 
878  sq_pushobject(v, ClassType<B>::ClassObject(v));
879  sq_newclass(v, true);
880  sq_getstackobj(v, -1, &classObj);
881  sq_addref(v, &classObj); // must addref before the pop!
882  sq_pop(v, 1);
883  if (className.empty())
884 #ifdef SQUNICODE
885  InitDerivedClass(v, string_to_wstring(typeid(*this).name()));
886 #else
887  InitDerivedClass(v, typeid(*this).name());
888 #endif
889  else InitDerivedClass(v, className);
890 
891  // install cleanup hook
892  HSQUIRRELVM *p = (HSQUIRRELVM *) sq_newuserdata(v, sizeof(v));
893  *p = v;
894 
895  sq_setreleasehook(v, -1, cleanup_hook);
896  // finish install cleanup hook
897  }
898  }
899 
900 protected:
901 
903 
904  void InitDerivedClass(HSQUIRRELVM vm, const string& className) {
905  ClassType<C>::CopyFunc(vm) = &A::Copy;
906  ClassType<C>::ClassName(vm) = className;
907  ClassType<C>::BaseClass(vm) = ClassType<B>::getClassTypeData(vm);
908 
909  // push the class
910  sq_pushobject(vm, ClassType<C>::ClassObject(vm));
911 
912  // set the typetag of the class
913  sq_settypetag(vm, -1, ClassType<C>::getClassTypeData(vm));
914  // add the default constructor
915  sq_pushstring(vm,_SC("constructor"), -1);
916  sq_newclosure(vm, &A::New, 0);
917  sq_newslot(vm, -3, false);
918 
919  // clone the base classes set table (static)
920  HSQOBJECT& setTable = ClassType<C>::SetTable(vm);
921  sq_resetobject(&setTable);
922  sq_pushobject(vm, ClassType<B>::SetTable(vm));
923  sq_pushstring(vm,_SC("__setTable"), -1);
924  sq_clone(vm, -2);
925  sq_remove(vm, -3);
926  sq_getstackobj(vm, -1, &setTable);
927  sq_addref(vm, &setTable);
928  sq_newslot(vm, -3, true);
929 
930  // clone the base classes get table (static)
931  HSQOBJECT& getTable = ClassType<C>::GetTable(vm);
932  sq_resetobject(&getTable);
933  sq_pushobject(vm, ClassType<B>::GetTable(vm));
934  sq_pushstring(vm,_SC("__getTable"), -1);
935  sq_clone(vm, -2);
936  sq_remove(vm, -3);
937  sq_getstackobj(vm, -1, &getTable);
938  sq_addref(vm, &getTable);
939  sq_newslot(vm, -3, true);
940 
941  // override _set
942  sq_pushstring(vm, _SC("_set"), -1);
943  sq_pushobject(vm, setTable); // Push the set table as a free variable
944  sq_newclosure(vm, sqVarSet, 1);
945  sq_newslot(vm, -3, false);
946 
947  // override _get
948  sq_pushstring(vm, _SC("_get"), -1);
949  sq_pushobject(vm, getTable); // Push the get table as a free variable
950  sq_newclosure(vm, sqVarGet, 1);
951  sq_newslot(vm, -3, false);
952 
953  // add weakref (apparently not provided by default)
954  sq_pushstring(vm, _SC("weakref"), -1);
955  sq_newclosure(vm, &Class<C, A>::ClassWeakref, 0);
956  sq_newslot(vm, -3, false);
957 
958  // add _typeof
959  sq_pushstring(vm, _SC("_typeof"), -1);
960  sq_newclosure(vm, &Class<C, A>::ClassTypeof, 0);
961  sq_newslot(vm, -3, false);
962 
963  // pop the class
964  sq_pop(vm, 1);
965  }
966 
968 };
969 
970 }
971 
972 #endif
Class & Ctor(const SQChar *name=0)
Definition: sqratClass.h:730
static HSQUIRRELVM Get()
Definition: sqratUtil.h:92
virtual HSQOBJECT GetObject() const
Definition: sqratClass.h:119
Class & GlobalFunc(const SQChar *name, F method)
Definition: sqratClass.h:371
Class & Ctor(const SQChar *name=0)
Definition: sqratClass.h:820
Class(HSQUIRRELVM v=DefaultVM::Get(), const string &className=string(), bool createClass=true)
Definition: sqratClass.h:86
Class & Prop(const SQChar *name, F1 getMethod, F2 setMethod)
Definition: sqratClass.h:232
Class & Ctor(const SQChar *name=0)
Definition: sqratClass.h:751
Class & GlobalProp(const SQChar *name, F1 getMethod, F2 setMethod)
Definition: sqratClass.h:263
Class & Ctor(const SQChar *name=0)
Definition: sqratClass.h:656
Class & StaticVar(const SQChar *name, V *var)
Definition: sqratClass.h:205
Function GetFunction(const SQChar *name)
Definition: sqratClass.h:466
Class & StaticOverload(const SQChar *name, F method)
Definition: sqratClass.h:430
Class & Ctor(const SQChar *name=0)
Definition: sqratClass.h:796
Class & Ctor(const SQChar *name=0)
Definition: sqratClass.h:773
Class & Prop(const SQChar *name, F getMethod)
Definition: sqratClass.h:292
Class & Overload(const SQChar *name, F method)
Definition: sqratClass.h:354
DerivedClass(HSQUIRRELVM v=DefaultVM::Get(), const string &className=string())
Definition: sqratClass.h:872
Definition: sqratClass.h:56
Class & GlobalProp(const SQChar *name, F getMethod)
Definition: sqratClass.h:314
Represents a function in Squirrel.
Definition: sqratFunction.h:40
Class & Func(const SQChar *name, F method)
Definition: sqratClass.h:333
Class & SetValue(const SQChar *name, const V &val)
Definition: sqratClass.h:166
Class & Ctor(const SQChar *name=0)
Definition: sqratClass.h:641
Class & StaticFunc(const SQChar *name, F method)
Definition: sqratClass.h:388
virtual HSQOBJECT & GetObject()
Definition: sqratClass.h:129
Class & GlobalOverload(const SQChar *name, F method)
Definition: sqratClass.h:409
Definition: sqratObject.h:48
Class & Ctor(const SQChar *name=0)
Definition: sqratClass.h:710
Class & Var(const SQChar *name, V C::*var)
Definition: sqratClass.h:183
Class & SetStaticValue(const SQChar *name, const V &val)
Definition: sqratClass.h:149
Class & SquirrelFunc(const SQChar *name, SQFUNCTION func)
Definition: sqratClass.h:448
Definition: sqratClass.h:843
Class & Ctor(const SQChar *name=0)
Definition: sqratClass.h:673
Class & Ctor(const SQChar *name=0)
Definition: sqratClass.h:691