changeset 26:6825fcc47e39

Added dstep.internal.Reflection
author Jacob Carlborg <doob@me.com>
date Tue, 06 Apr 2010 11:38:08 +0200
parents b9de51448c6b
children 57371c29ef73
files dstep/internal/Reflection.d
diffstat 1 files changed, 345 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dstep/internal/Reflection.d	Tue Apr 06 11:38:08 2010 +0200
@@ -0,0 +1,345 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Mar 8, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module dstep.internal.Reflection;
+
+import dstep.objc.bridge.Bridge;
+import dstep.internal.String;
+
+/**
+ * Returns the name of the given function
+ * 
+ * Params:
+ *     func = the function alias to get the name of
+ *     
+ * Returns: the name of the function 
+ */
+template functionNameOf (alias func)
+{
+	version(LDC)
+		const functionNameOf = (&func).stringof[1 .. $];
+	
+	else
+		const functionNameOf = (&func).stringof[2 .. $];
+}
+
+/**
+ * Returns the parameter names of the given function
+ * 
+ * Params:
+ *     func = the function alias to get the parameter names of
+ *     
+ * Returns: an array of strings containing the parameter names 
+ */
+template parameterNamesOf (alias func)
+{
+	const parameterNamesOf = parameterNamesOfImpl!(func);
+}
+
+private string[] parameterNamesOfImpl (alias func) ()
+{
+	string funcStr = typeof(&func).stringof;
+
+	auto start = funcStr.indexOf('(');
+	auto end = funcStr.indexOf(')');
+	
+	const firstPattern = ' ';
+	const secondPattern = ',';
+	
+	funcStr = funcStr[start + 1 .. end];
+	
+	if (funcStr == "")
+		return null;
+		
+	funcStr ~= secondPattern;
+	
+	string token;
+	string[] arr;
+	
+	foreach (c ; funcStr)
+	{		
+		if (c != firstPattern && c != secondPattern)
+			token ~= c;
+		
+		else
+		{			
+			if (token)
+				arr ~= token;
+			
+			token = null;
+		}			
+	}
+	
+	if (arr.length == 1)
+		return arr;
+	
+	string[] result;
+	bool skip = false;
+	
+	foreach (str ; arr)
+	{
+		skip = !skip;
+		
+		if (skip)
+			continue;
+		
+		result ~= str;
+	}
+	
+	return result;
+}
+
+/**
+ * Compile-time function to get the index of the give element.
+ * 
+ * Performs a linear scan, returning the index of the first occurrence 
+ * of the specified element in the array, or U.max if the array does 
+ * not contain the element.
+ * 
+ * Params:
+ *     arr = the array to get the index of the element from
+ *     element = the element to find
+ *     
+ * Returns: the index of the element or size_t.max if the element was not found.
+ */
+private size_t indexOf (T) (T[] arr, T element)
+{
+	foreach (i, e ; arr)
+		if (e == element)
+			return i;
+	
+	return size_t.max;
+}
+
+//FIXME fix this when http://d.puremagic.com/issues/show_bug.cgi?id=3512 is fixed
+version (none)
+{
+
+/**
+ * Compile-time function to get the index of the give element.
+ * 
+ * Performs a linear scan, returning the index of the first occurrence 
+ * of the specified element in the array, or U.max if the array does 
+ * not contain the element.
+ * 
+ * Params:
+ *     arr = the array to get the index of the element from
+ *     element = the element to find
+ *     
+ * Returns: the index of the element or size_t.max if the element was not found.
+ */
+private size_t indexOf (T) (T[] arr, dchar element)
+{
+	static assert(is(T == char) || is(T == wchar) || is(T == dchar), `dstep.internal.Traits.indexOf: The given type "` ~ T.stringof ~ `" is not valid, it has to be char, wchar or dchar`);
+	
+	foreach (i, dchar e ; arr)
+		if (e == element)
+			return i;
+	
+	return size_t.max;
+}
+}
+
+/**
+ * Evaluates to true if $(D_PARAM T) has a instance method with the given name
+ * 
+ * Params:
+ * 		T = the type of the class/struct
+ * 		method = the name of the method
+ */
+template hasInstanceMethod (T, string method)
+{
+	const hasInstanceMethod = is(typeof({
+		T t;
+		mixin("auto f = &t." ~ method ~ ";");
+	}));
+}
+
+/**
+ * Evaluates to true if $(D_PARAM T) has a class method with the given name
+ * 
+ * Params:
+ * 		T = the type of the class/struct
+ * 		method = the name of the method
+ */
+template hasClassMethod (T, string method)
+{
+	const hasClassMethod = is(typeof({
+		mixin("auto f = &T." ~ method ~ ";");
+	}));
+}
+
+/**
+ * Evaluates to true if $(D_PARAM T) has a either a class method or a instance method
+ * with the given name.
+ * 
+ * Params:
+ * 		T = the type of the class/struct
+ * 		method = the name of the method
+ */
+template hasMethod (T, string method)
+{
+	const hasMethod = hasClassMethod!(T, method) || hasInstanceMethod!(T, method);
+}
+
+/**
+ * Evaluates to true if T has a field with the given name
+ * 
+ * Params:
+ * 		T = the type of the class/struct
+ * 		field = the name of the field
+ */
+template hasField (T, string field)
+{
+	const hasField = hasFieldImpl!(T, field, 0);
+}
+
+private template hasFieldImpl (T, string field, size_t i)
+{
+	static if (T.tupleof.length == i)
+		const hasFieldImpl = false;
+	
+	else static if (T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] == field)
+		const hasFieldImpl = true;
+	
+	else
+		const hasFieldImpl = hasFieldImpl!(T, field, i + 1);		
+}
+
+/// Evaluates to true if $(D_PARAM T) has binded methods
+template hasBindedMethods (T)
+{
+	const bool hasBindedMethods = hasField!(T, Bridge.objcClassMethodDeclarationVar) || hasField!(T, Bridge.objcMethodDeclarationVar);
+}
+
+
+
+/**
+ * Sets the given value to the filed with the given name
+ * 
+ * Params:
+ *     t = an instance of the type that has the field
+ *     value = the value to set
+ */
+void setValueOfField (string field, T, U) (ref T t, U value)
+in
+{
+	static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
+}
+body
+{
+	const len = T.stringof.length; 
+	
+	foreach (i, dummy ; typeof(T.tupleof))
+	{
+		const f = T.tupleof[i].stringof[1 + len + 2 .. $];
+		
+		static if (f == field)
+		{
+			t.tupleof[i] = value;
+			break;
+		}
+	}
+}
+
+/**
+ * Evaluates to the type of the field with the given name
+ * 
+ * Params:
+ * 		T = the type of the class/struct
+ * 		field = the name of the field
+ */
+template TypeOfField (T, string field)
+{
+	static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
+
+	alias TypeOfFieldImpl!(T, field, 0) TypeOfField;
+}
+
+private template TypeOfFieldImpl (T, string field, size_t i)
+{
+	static if (T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] == field)
+		alias typeof(T.tupleof[i]) TypeOfFieldImpl;
+	
+	else
+		alias TypeOfFieldImpl!(T, field, i + 1) TypeOfFieldImpl;
+}
+
+/**
+ * Creates a new instance of class with the given name
+ * 
+ * Params:
+ *     name = the fully qualified name of the class
+ *     args = the arguments to the constructor
+ *     
+ * Returns: the newly created instance or null
+ */
+T factory (T : Object, ARGS...) (string name, ARGS args)
+{	
+	auto classInfo = ClassInfo.find(name);
+	
+	if (!classInfo)
+		return null;
+	
+	auto object = newInstance(classInfo);
+	
+	if (classInfo.flags & 8 && classInfo.defaultConstructor is null)
+	{
+		auto o = cast(T) object;
+		
+		static if (is(typeof(o._ctor(args))))
+			return o._ctor(args);
+		
+		else
+			return null;
+	}
+	
+	else
+	{
+		if (classInfo.flags & 8 && classInfo.defaultConstructor !is null)
+		{
+			Object delegate () ctor;
+			ctor.ptr = cast(void*) object;
+			ctor.funcptr = cast(Object function()) classInfo.defaultConstructor;
+			
+			return cast(T) ctor();
+		}
+		
+		else
+			return cast(T) object;
+	}
+}
+
+private
+{
+	version (LDC)
+		extern (C) Object _d_allocclass(ClassInfo);
+	
+	else
+		extern (C) Object _d_newclass(ClassInfo);
+}
+
+/**
+ * Creates a new instance of the given ClassInfo
+ * 
+ * Params:
+ *     classInfo = the class to create a new instance of
+ *     
+ * Returns: the new instance
+ */
+Object newInstance (ClassInfo classInfo)
+{
+	version (LDC)
+	{		
+		Object object = _d_allocclass(classInfo);
+        (cast(byte*) object)[0 .. classInfo.init.length] = classInfo.init[];
+        
+        return object;
+	}
+
+	else
+		return _d_newclass(classInfo);
+}
\ No newline at end of file