diff d2/qtd/QtdObject.d @ 372:a032df77b6ab

Simple debug helper. Unittests. Meta-object for polymorphic non-QObjects
author Max Samukha <maxter@spambox.com>
date Thu, 08 Jul 2010 17:19:05 +0300
parents 9784459f0750
children 1d56b2a2e10c
line wrap: on
line diff
--- a/d2/qtd/QtdObject.d	Sun Jul 04 14:17:49 2010 +0100
+++ b/d2/qtd/QtdObject.d	Thu Jul 08 17:19:05 2010 +0300
@@ -1,75 +1,330 @@
 /**
 *
-*  Copyright: Copyright QtD Team, 2008-2009
-*  License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>
-*
-*  Copyright QtD Team, 2008-2009
-*  Distributed under the Boost Software License, Version 1.0.
-*  (See accompanying file boost-license-1.0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+*  Copyright: Copyright QtD Team, 2008-2010
+*  License: Boost License 1.0
+*  Authors: Max Samukha, Eldar Insafutdinov
 *
 */
 
 module qtd.QtdObject;
-import qtd.Core;
 
-enum QtdObjectFlags : ubyte
+import
+    core.memory,
+    std.bitmanip,
+    qtd.Core,
+    qtd.Debug,
+    qtd.meta.Runtime;  
+
+/**
+    QtdObject initialization options.
+ */
+enum QtdObjectInitFlags
 {
     none,
-    nativeOwnership           = 0x1,
-    dOwnership                = 0x2,
-    dynamicEntity             = 0x4
-    //gcManaged               = 0x4
+    /// The wrapper is being created by user code.
+    createdByD              = 0x1,
+    /// The wrapper is being created with native ownership.
+    nativeOwnership         = 0x2,
+    /// The wrapper is allocated on stack.
+    onStack                 = 0x4
+}
+
+/**
+ */
+enum QtdObjectOwnership
+{
+    ///
+    native,
+    ///
+    d
+}
+
+/**
+ */
+struct QtdObjectFlags
+{
+    mixin (bitfields!(
+        bool, "nativeDeleteDisabled"        , 1,
+        bool, "wrapperDeleteDisabled"       , 1,
+        bool, "createdByD"                  , 1,
+        bool, "pinned"                      , 1,
+        bool, "isQObject"                   , 1,
+        bool, "polymorphic"                 , 1,
+        bool, "onStack"                     , 1,
+        int , "reserved"                    , 1
+    ));
 }
 
-package abstract class QtdObject
+
+/* package */ abstract class QtdObject
 {
-    protected QtdObjectFlags __flags_;
-    void* __nativeId;
+    alias typeof(this) This;
+
+    private
+    {
+        void* _nativeId;
+        This _next;
+        This _prev;
+        __gshared static This _root;
+    }
+
+    protected QtdObjectFlags _flags;
+
+    /**
+     */
+    @property QtdObjectFlags qtdFlags()
+    {
+        return _flags;
+    }
 
-    this(void* nativeId, QtdObjectFlags flags = QtdObjectFlags.none)
+    /**
+     */
+    @property final const
+    {
+        void* qtdNativeId()
+        {
+            return cast(void*)_nativeId;
+        }
+
+        void qtdNativeId(void* v)
+        {
+            unqual(_nativeId) = v;
+        }
+    }
+
+    this(void* nativeId, QtdObjectInitFlags initFlags = QtdObjectInitFlags.none)
     {
-        __nativeId = nativeId;
-        __flags_ = flags;
+        _nativeId = nativeId;
+
+        if (initFlags & QtdObjectInitFlags.createdByD)
+            _flags.createdByD = true;
+
+        if (initFlags & QtdObjectInitFlags.nativeOwnership)
+            qtdSetOwnership(QtdObjectOwnership.native);
+
+        if (initFlags & QtdObjectInitFlags.onStack)
+        {
+            //assert(!_flags.isQObject);
+            assert(!(initFlags & QtdObjectInitFlags.nativeOwnership));
+
+            _flags.nativeDeleteDisabled = true;
+            _flags.wrapperDeleteDisabled = true;
+        }
+
+        mixin(debugHandler("onWrapperConstructed", "this"));
     }
 
-    final QtdObjectFlags __flags()
+    /**
+        Disables GC for this object;
+     */
+    // TODO: needs to be properly synchronized
+    final void qtdPin() const
     {
-        return __flags_;
+        assert(!_flags.pinned);
+        //GC.addRoot(cast(void*)this);
+
+        auto obj = unqual(this);
+
+        obj._next = _root;
+        _root = obj;
+        if (_next)
+            obj._next._prev = obj;
+
+        obj._flags.pinned = true;
+    }
+
+    /**
+        Multiple wrappers for a single native object may exist.
+        This function is used to test that this and the other wrapper point
+        to the same native object (identity test).
+
+        Note that wrappers for QObject instances and instances of classes
+        derived from QObject are always unique, therefore
+        the 'is' expression can be used instead of this function.
+     */
+    final bool isSame(const(QtdObject) other) const
+    {
+        return other !is null && (other is this || other.qtdNativeId == qtdNativeId);
     }
 
-    /+ final +/ void __setFlags(QtdObjectFlags flags, bool value)
+    /**
+        Enables GC for this object.
+     */
+    // TODO: needs to be properly synchronized
+    final void qtdUnpin() const
     {
-        if (value)
-            __flags_ |= flags;
+        assert(_flags.pinned);
+        //GC.removeRoot(cast(void*)this);
+
+        auto obj = unqual(this);
+        if (_prev)
+            obj._prev._next = obj._next;
         else
-            __flags_ &= ~flags;
+            _root = obj._next;
+
+        if (_next)
+            obj._next._prev = obj._prev;
+
+        obj._flags.pinned = false;
+    }
+
+    /**
+        Sets the ownership of this object.
+        Setting the same ownership twice results in undefined behavior.
+        The function is not thread-safe.
+     */
+    void qtdSetOwnership(QtdObjectOwnership own) const
+    {
+        if (_flags.isQObject)
+            return;
+
+        assert(!_flags.onStack);
+        auto obj = unqual(this);
+
+        if (own == QtdObjectOwnership.native)
+        {
+            if (_flags.polymorphic && _flags.createdByD)
+                qtdPin();
+            else
+                obj._flags.nativeDeleteDisabled = true;
+        }
+        else if (own == QtdObjectOwnership.d)
+        {
+            if (_flags.polymorphic && _flags.createdByD)
+                qtdUnpin();
+            else
+                obj._flags.nativeDeleteDisabled = false;
+        }
+        else
+            assert(false);
+
+        mixin(debugHandler("onWrapperOwnershipChanged", "obj"));
     }
 
     // COMPILER BUG: 3206
-    protected void __deleteNative()
+    protected void qtdDeleteNative()
     {
         assert(false);
     }
 
     ~this()
     {
-        if (!(__flags_ & QtdObjectFlags.nativeOwnership))
+        mixin(debugHandler("onWrapperDestruction", "this"));
+
+        if (!_flags.nativeDeleteDisabled)
         {
             // avoid deleting D object twice.
-            __flags_ |= QtdObjectFlags.dOwnership;
-            __deleteNative;
+
+            _flags.wrapperDeleteDisabled = true;
+            qtdDeleteNative;
+
+            mixin(debugHandler("onNativeDeleted", "this"));
         }
+
+        if (_flags.pinned)
+            qtdUnpin();
+
+        mixin(debugHandler("onWrapperDestroyed", "this"));
+    }
+}
+
+/**
+    Base class for polymorphic non-QObjects (TBD).
+ */
+/* package */ abstract class NonQObject : QtdObject
+{
+    alias NonQObjectMetaClass Meta;
+
+    this(void* nativeId, QtdObjectInitFlags initFlags)
+    {
+        _flags.polymorphic = true;
+        super(nativeId, initFlags);
     }
 }
 
+/**
+    Base class for QtD meta-object classes.
+ */
+abstract class QtdMetaClass : MetaClass
+{
+    alias QtdObject function(void* nativeId, QtdObjectInitFlags initFlags) CreateWrapper;
+
+    private void* _nativeId;
+    protected CreateWrapper _createWrapper;
+
+    this() {}
+
+    /**
+     */
+    @property
+    void* nativeId()
+    {
+        return _nativeId;
+    }
+
+    void construct(T)()
+    {
+        super.construct!T();
+        _nativeId = T.qtdNativeStaticMetaObject();
+        _createWrapper = &T.qtdCreateWrapper;
+    }
+
+    abstract QtdObject getWrapper(void* nativeId, QtdObjectInitFlags initFlags = QtdObjectInitFlags.none);
+}
+
+/**
+    Meta-object class for non-QObject polymorphic classes.
+ */
+final class NonQObjectMetaClass : QtdMetaClass
+{
+    alias typeof(this) This;
+    alias createImpl!This create;
+
+    @property override This next()
+    {
+        return static_cast!This(super.next);
+    }
+
+    @property override This firstDerived()
+    {
+        return static_cast!This(super.firstDerived);
+    }
+
+    override QtdObject getWrapper(void* nativeId, QtdObjectInitFlags initFlags)
+    {
+        // traverse the inheritance tree to find a matching meta-object.
+        // if the exact match is not found, return the closest base.
+        This lookUp(This mo)
+        {
+            if (!qtdTypeInfosEqual(mo.nativeId, nativeId))
+            {
+                for (auto mo2 = mo.firstDerived; mo2 !is null; mo2 = mo2.next)
+                {
+                    mo2 = lookUp(mo2);
+                    if (mo != mo2)
+                        break;
+                }
+            }
+            return mo;
+        }
+
+        auto mo = lookUp(this);
+        return static_cast!NonQObject(mo._createWrapper(nativeId, initFlags));
+    }
+}
+
+extern (C) bool qtdTypeInfosEqual(void* info1, void* info2);
+
 mixin(qtdExport("void", "QtdObject_delete", "void* dId",
     q{
         auto obj = cast(QtdObject)dId;
 
-        if (!(obj.__flags & QtdObjectFlags.dOwnership))
+        mixin(debugHandler("onDeletingWrapperFromNative", "dId"));
+
+        if (!obj._flags.wrapperDeleteDisabled)
         {
             // Avoid deleting native object twice
-            obj.__setFlags(QtdObjectFlags.nativeOwnership, true);
+            obj._flags.nativeDeleteDisabled = true;
             delete obj;
         }
     }));