Sq Plus Native Created Instances With Correct Ancestry
Last changed: -220.211.116.217

.

(Fixed at snapshot 07/01/07 kkawachi)

To expose the bug:

 #include <string>
 #include <sqplus.h>


 class Base 
 {
        public:
                Base() {}
                virtual ~Base() {}


                static void Bind()
                {
                        SqPlus::SQClassDef<Base>(_T("Base")).
                                func(&Base::GetBaseId,"getBaseId");
                }


                std::string GetBaseId() { return "Base"; }


 };


 DECLARE_INSTANCE_TYPE(Base);


 class Derived : public Base 
 {


        public:
                Derived() : Base() {}
                virtual ~Derived() {}


                static void Bind()
                {
                        SqPlus::SQClassDef<Derived>(_T("Derived"),_T("Base")).
                                staticFunc( &Derived::GetNativeCreated, "getNativeCreated" );
                                func( &Derived::GetDerivedId, "getDerivedId");
                }


                std::string GetDerivedId() { return "Derived"; }


                static Derived* GetNativeCreated() { return instance; }


      private:
                static Derived* instance;
 };


 Derived* Derived::instance = new Derived();


 DECLARE_INSTANCE_TYPE(Derived);


 int _tmain(int argc, _TCHAR* argv[])
 {
      printf("Initialize Squirrel\n");
      SquirrelVM::Init();
      printf("Binding classes to squirrel\n");
      Base::Bind();
      Derived::Bind();


      try
      {
                SquirrelObject script = SquirrelVM::CompileBuffer(_T(
                        " \
                                local shouldWork = Derived(); \
                                print(\"Base id is \" + shouldWork.getBaseId()); \
                                local shouldFail = shouldWork.getNativeCreated(); \
                                print(\"Base id is \" + shouldFail.getBaseId()); \
                        "
                ));


                SquirrelVM::RunScript(script);
        }
        catch(SquirrelError& error)
        {
                printf("Error: %s\n",std::string(error.desc).c_str());
        }
 }

To fix it:

In sqplus.h add this after #define SQ_ANCESTOR_CLASS_INDEX T("_ci")

 #define SQ_CLASS_HEIRARCHY_TABLE _T("__ch")


 inline void PopulateAncestry(HSQUIRRELVM v, SquirrelObject& instance, SQUserPointer up) {


        int oldtop = sq_gettop(v);
        SquirrelObject objectTable = SquirrelVM::CreateTable();
      instance.SetValue(SQ_CLASS_OBJECT_TABLE_NAME,objectTable);


        SquirrelObject root = SquirrelVM::GetRootTable();
        if (root.Exists(SQ_CLASS_HEIRARCHY_TABLE))
        {
                SquirrelObject classHeirarchyTable = root.GetValue(SQ_CLASS_HEIRARCHY_TABLE);
                SQUserPointer myTypeTag;
                if(instance.GetTypeTag(&myTypeTag))
                {
                        SquirrelObject classHierArray = classHeirarchyTable.GetValue(INT(size_t(myTypeTag)));
                        if(OT_ARRAY == classHierArray.GetType())
                        {
                                INT count = classHierArray.Len();
                                for (INT i=0; i < count; i++) {
                                        SquirrelObject so = classHierArray.GetValue(i);
                                        sq_pushobject(v,so.GetObjectHandle());
                                        SQUserPointer typeTag;
                                        sq_gettypetag(v,-1,&typeTag);
                                        objectTable.SetUserPointer(INT(size_t(typeTag)),up);
                                        sq_poptop(v); 
                                } // for
                        }
                }
        }
        sq_settop(v,oldtop);
 }

Replace the PostConstruct function with this

 template<typename T>
 inline int PostConstruct(HSQUIRRELVM v,T * newClass,SQRELEASEHOOK hook) {


 #ifdef SQ_USE_CLASS_INHERITANCE
  StackHandler sa(v);
  HSQOBJECT ho = sa.GetObjectHandle(1); // OT_INSTANCE
  SquirrelObject instance(ho);
  PopulateAncestry(v,instance,newClass);
 #endif


  sq_setinstanceup(v,1,newClass);
  sq_setreleasehook(v,1,hook);
  return 1;
 } // PostConstruct

replace the RegisterClassType function with

 template<typename T>
 inline SquirrelObject RegisterClassType(HSQUIRRELVM v,const SQChar * scriptClassName, const SQChar * baseScriptClassName=0) {
   int top = sq_gettop(v);
   SquirrelObject newClass;
   if (CreateClass(v,newClass,(SQUserPointer)ClassType<T>::type(),scriptClassName,baseScriptClassName)) {
        SquirrelVM::CreateFunction(newClass,&ConstructReleaseClass<T>::construct,_T("constructor"));


 #ifdef SQ_USE_CLASS_INHERITANCE


    // <NOTE> New member vars cannot be added to instances (OT_INSTANCE): additions must occur on the defining class (OT_CLASS), before any instances are instantiated.
    if (!newClass.Exists(SQ_CLASS_OBJECT_TABLE_NAME)) { // Will always get table from most-derived registered class.
      SquirrelObject objectTable = SquirrelVM::CreateTable();
      newClass.SetValue(SQ_CLASS_OBJECT_TABLE_NAME,objectTable); // Constructors must add their 'this' pointer indexed by type to this table. See PostConstruct() above.
                                                                 // 11/2/05: This table will behave as a static global for each instance unless overwritten during construction (see PostConstruct() above).
    } // if


        SquirrelObject root = SquirrelVM::GetRootTable();
        SquirrelObject classHeirarchyTable; 
        if (!root.Exists(SQ_CLASS_HEIRARCHY_TABLE))
        {
                classHeirarchyTable = SquirrelVM::CreateTable();
                root.SetValue(SQ_CLASS_HEIRARCHY_TABLE,classHeirarchyTable);
        }
        else
        {
                classHeirarchyTable = root.GetValue(SQ_CLASS_HEIRARCHY_TABLE);
        }


        if(0 != baseScriptClassName)
        {
                if(root.Exists(baseScriptClassName))
                {
                        SquirrelObject baseClass = root.GetValue(baseScriptClassName);
                        SQUserPointer baseType;
                        if(baseClass.GetTypeTag(&baseType))
                        {
                                SquirrelObject classHierArray = classHeirarchyTable.GetValue((INT(size_t(baseType))));
                                if(OT_ARRAY == classHierArray.GetType())
                                {
                                        SquirrelObject newArray = classHierArray.Clone();
                                        newArray.ArrayAppend(newClass);
                                        classHeirarchyTable.SetValue((INT(size_t(ClassType<T>::type()))),newArray);
                                }
                        }
                }
        }
        else
        {
                SquirrelObject newArray = SquirrelVM::CreateArray(0);
                newArray.ArrayAppend(newClass);
                classHeirarchyTable.SetValue((INT(size_t(ClassType<T>::type()))),newArray);
        }


 #endif
   } // if
   sq_settop(v,top);
   return newClass;
 } // RegisterClassType

In SquirrelBindingsUtils.h replace CreateNativeClassInstance with this

 BOOL CreateNativeClassInstance(HSQUIRRELVM v,const SQChar *classname,SQUserPointer ud,SQRELEASEHOOK hook)
 {
        int oldtop = sq_gettop(v);
        sq_pushroottable(v);
        sq_pushstring(v,classname,-1);
        if(SQ_FAILED(sq_rawget(v,-2))){ // Get the class (created with sq_newclass()).
                sq_settop(v,oldtop);
                return FALSE;
        }
        //sq_pushroottable(v);
        if(SQ_FAILED(sq_createinstance(v,-1))) {
                sq_settop(v,oldtop);
                return FALSE;
        }


 #ifdef SQ_USE_CLASS_INHERITANCE
        HSQOBJECT ho;
        sq_getstackobj(v,-1,&ho); // OT_INSTANCE
        SquirrelObject instance(ho);
        SqPlus::PopulateAncestry(v,instance,ud);
 #endif


        sq_remove(v,-3); //removes the root table
        sq_remove(v,-2); //removes the class
        if(SQ_FAILED(sq_setinstanceup(v,-1,ud))) {
                sq_settop(v,oldtop);
                return FALSE;
        }
        sq_setreleasehook(v,-1,hook);
        return TRUE;
 }

auto insurance price quote