Mercurial > projects > qtd
view d2/qtd/meta/Runtime.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 | 185df9220ea7 |
children |
line wrap: on
line source
/************************************************************************** Copyright: Copyright Max Samukha, 2010 Authors: Max Samukha License: Boost Software License 1.0 **************************************************************************/ module qtd.meta.Runtime; import qtd.meta.Compiletime, std.typetuple, std.conv, std.stdio, std.traits, std.variant; import std.range : isForwardRange, isRandomAccessRange; /** Object to lock on when accessing thread-shared meta-objects. */ immutable Object metaLock; shared static this() { metaLock = cast(immutable)new Object; } /** IDs of the built-in basic types. */ enum BasicTypeId { /// void_, /// bool_, /// byte_, /// ubyte_, /// short_, /// ushort_, /// int_, /// uint_, /// long_, /// ulong_, /// cent_, /// ucent_, /// float_, /// double_, /// real_, /// ifloat_, /// idouble_, /// ireal_, /// cfloat_, /// cdouble_, /// creal_, /// char_, /// wchar_, /// dchar_ } /** Thrown on meta-system errors. */ class MetaException : Exception { this(string msg) { super(msg); } } /** All meta-object classes inherit from this base class. */ abstract class MetaBase { alias typeof(this) This; string name; MetaAttribute[] attributes; protected MetaBase[] members_; template createImpl(M : This) { static M createImpl(alias symbol)() { auto m = new M; m.construct!symbol; return m; } } private void createAttrs(alias symbol)() { alias GetAttributes!symbol attrs; enum len = attrs.length; // COMPILER BUG foreach (i, _; Repeat!(void, len)) { alias TypeTuple!(attrs[i].tuple) attr; // if the third element of the attribute data is a MetaAttribute subclass, // use that to create the attribute instance. static if (attr.length > 2 && (is(attr[2] : MetaAttribute))) { alias attr[2] MA; alias TypeTuple!(attr[0..2], attr[3..$]) args; attributes ~= MA /*COMPILER BUG: tuple element as tuple*/[0].create(args); } } } protected void construct(alias symbol)() { name = symbol.stringof; createAttrs!symbol; } static struct MembersRange { private MetaBase[] members_; @property MetaBase front() { return members_[0]; } @property bool empty() { return members_.length == 0; } @property MembersRange save() { return this; } @property MetaBase back() { return members_[$ - 1]; } void popFront() { members_ = members_[1..$]; } void popBack() { members_ = members_[0..$ - 1]; } MetaBase opIndex(size_t i) { return members_[i]; } @property size_t length() { return members_.length; } } /** Returns a random access range of members of the class described by this meta-object. */ @property MembersRange members() { return MembersRange(members_); } } version (QtdUnittest) unittest { static assert(isRandomAccessRange!(MetaBase.MembersRange)); } /** Base class for run-time attributes. */ abstract class MetaAttribute { string name; AttributeOptions options; this(string name, AttributeOptions opts) { this.name = name; options = opts; } } abstract class MetaType : MetaBase { } abstract class MetaAggregate : MetaType { } class MetaClass : MetaAggregate { alias typeof(this) This; private { This base_; This firstDerived_; This next_; ClassInfo classInfo_; } alias createImpl!This create; static struct AllMembersRange { private { This metaClass_; MetaBase[] members_; void skipEmpty() { while (!metaClass_.members_.length) { metaClass_ = metaClass_.base_; if (!metaClass_) return; } members_ = metaClass_.members_; } } this(This metaClass) { metaClass_ = metaClass; skipEmpty(); } @property MetaBase front() { return members_[0]; } @property bool empty() { return members_.length == 0; } @property AllMembersRange save() { return this; } void popFront() { members_ = members_[1..$]; if (!members_.length) { metaClass_ = metaClass_.base_; if (metaClass_) skipEmpty(); } } } /** Returns a forward range of members of the class described by this meta-object, including base class members. */ @property AllMembersRange allMembers() { return AllMembersRange(this); } /** Returns the meta-object of the base class. */ @property This base() { return base_; } /** Returns the next meta-object on this level of the inheritance hierarchy. */ @property This next() { return next_; } /** Returns the meta-object for the first derived class. */ @property This firstDerived() { return firstDerived_; } /** D class info. */ @property ClassInfo classInfo() { return classInfo_; } /* internal */ void construct(T : Object)() { super.construct!T(); classInfo_ = T.classinfo; static if (!is(T == Object)) { alias BaseClassesTuple!(T)[0] Base; base_ = meta!Base; next_ = base_.firstDerived_; base_.firstDerived_ = this; } } /** */ override string toString() const { return "MetaClass for " ~ classInfo_.name; } } version (QtdUnittest) unittest { static assert (isForwardRange!(MetaClass.AllMembersRange)); } class MetaStruct : MetaAggregate { alias typeof(this) This; alias createImpl!This create; } /** */ @property M meta(alias symbol, M : MetaBase)() { __gshared static M sharedM; static M m; if (!m) { synchronized(metaLock) { if (!sharedM) sharedM = M.create!symbol; } m = sharedM; } return m; } /** */ // only classes and structs for now @property auto meta(T)() { static if (is(T.Meta)) return meta!(T, T.Meta); else static if (is(T == class)) return meta!(T, MetaClass); else static if (is(T == struct)) return meta!(T, MetaStruct); else static assert(false, "No meta-object for symbol " ~ T.stringof); } /** A run-time attribute implementation that stores the attribute data in an array of variants. */ class MetaVariantAttribute : MetaAttribute { alias typeof(this) This; Variant[] values; private this(string name, AttributeOptions opts) { super(name, opts); } static MetaVariantAttribute create(A...)(string name, AttributeOptions opts, A args) { auto ret = new This(name, opts); foreach(i, _; A) ret.values ~= Variant(args[i]); return ret; } } /** A run-time attribute implementation that stores the attribute data in an assiciative array of variants. */ class MetaVariantDictAttribute : MetaAttribute { Variant[string] values; alias typeof(this) This; private this(string name, AttributeOptions opts) { super(name, opts); } static This create(A...)(string name, AttributeOptions opts, A args) { auto ret = new This(name, opts); foreach(i, _; A) ret.values[args[i]] = Variant(args[i + 1]); // PHOBOS BUG: phobos asserts on this return ret; } } version(QtdUnittest) unittest { enum x = 42; static void foo() {} static class C { mixin InnerAttribute!("variantAttribute", MetaVariantAttribute, "22", x, 33); /+ PHOBOS BUG: variant is unusable with AAs mixin InnerAttribute!("variantDictAttribute", MetaVariantDictAttribute, "a", "33", "b", 44, "c", x ); +/ } auto attrs = meta!(C).attributes; assert(attrs.length == 1); auto attr = cast(MetaVariantAttribute)attrs[0]; assert(attr.name == "variantAttribute"); assert(attr.values[0] == "22"); assert(attr.values[1] == x); assert(attr.values[2] == 33); /+ auto attr2 = cast(MetaVariantDictAttribute) attrs[1]; assert(attr2.name == "variantDictAttribute"); //assert(attr2.values["a"] == "33"); //assert(attr2.values["b"] == 44); //assert(attr2.values["c"] == x); +/ }