Mercurial > projects > qtd
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; } }));