diff orange/util/Reflection.d @ 1:11a31bd929f9

Removed dependency on private library
author Jacob Carlborg <doob@me.com>
date Mon, 31 May 2010 16:06:36 +0200
parents f7b078e85f7f
children 32152d5fad4b
line wrap: on
line diff
--- a/orange/util/Reflection.d	Wed May 26 17:19:13 2010 +0200
+++ b/orange/util/Reflection.d	Mon May 31 16:06:36 2010 +0200
@@ -1,9 +1,468 @@
 /**
- * Copyright: Copyright (c) 2010 Jacob Carlborg.
+ * Copyright: Copyright (c) 2009 Jacob Carlborg.
  * Authors: Jacob Carlborg
- * Version: Initial created: Jan 26, 2010
+ * Version: Initial created: Oct 5, 2009
  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
  */
 module orange.util.Reflection;
 
-public import mambo.util.Reflection;
\ No newline at end of file
+import orange.util.CTFE;
+import orange.util.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);
+}
+
+/**
+ * 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 
+ */
+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;
+}
+
+/**
+ * Helper function for callWithNamedArguments
+ * 
+ * Returns:
+ */
+private string buildFunction (alias func, string args) ()
+{
+	const str = split(args);
+	string[] params;
+	string[] values;
+	auto mixinString = functionNameOf!(func) ~ "(";
+	
+	foreach (s ; str)
+	{
+		auto index = s.indexOf('=');
+		params ~= s[0 .. index];
+		values ~= s[index + 1 .. $];
+	}		
+
+	const parameterNames = parameterNamesOf!(func);
+
+	foreach (i, s ; parameterNames)
+	{
+		auto index = params.indexOf(s);
+		
+		if (index != params.length)
+			mixinString ~= values[index] ~ ",";
+	}
+	
+	return mixinString[0 .. $ - 1] ~ ");";
+}
+
+/**
+ * Calls the given function with named arguments
+ * 
+ * Params:
+ *     func = an alias to the function to call
+ *     args = a string containing the arguments to call using this syntax: `arg2=value,arg1="value"`
+ */
+void callWithNamedArguments (alias func, string args) ()
+{
+	mixin(buildFunction!(func, args));
+}
+
+/**
+ * Evaluates to true if 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 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 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 an array of strings containing the names of the fields in the given type
+ */
+template fieldsOf (T)
+{
+	const fieldsOf = fieldsOfImpl!(T, 0);
+}
+
+/**
+ * Implementation for fieldsOf
+ * 
+ * Returns: an array of strings containing the names of the fields in the given type
+ */
+template fieldsOfImpl (T, size_t i)
+{
+	static if (T.tupleof.length == 0)
+		const fieldsOfImpl = [""];
+	
+	else static if (T.tupleof.length - 1 == i)
+		const fieldsOfImpl = [T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $]];
+	
+	else
+		const fieldsOfImpl = T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] ~ fieldsOfImpl!(T, i + 1);
+}
+
+/**
+ * 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;
+}
+
+/**
+ * Evaluates to a string containing the name of the field at given position in the type given type.
+ * 
+ * Params:
+ * 		T = the type of the class/struct
+ * 		position = the position of the field in the tupleof array
+ */
+template nameOfFieldAt (T, size_t position)
+{
+	static if (T.tupleof[position].stringof.length > T.stringof.length + 3)
+		const nameOfFieldAt = T.tupleof[position].stringof[1 + T.stringof.length + 2 .. $];
+	
+	else
+		const nameOfFieldAt = "";
+}
+
+/**
+ * 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 (T, U, string field) (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;
+		}
+	}
+}
+
+/**
+ * Gets the value of the field with the given name
+ * 
+ * Params:
+ *     t = an instance of the type that has the field
+ *      
+ * Returns: the value of the field
+ */
+U getValueOfField (T, U, string field) (T t)
+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)
+			return t.tupleof[i];
+	}
+}
+
+/**
+ * Gets all the class names in the given string of D code
+ * 
+ * Params:
+ *     code = a string containg the code to get the class names from	
+ * 
+ * Returns: the class names
+ */
+string[] getClassNames (string code) ()
+{
+	const fileContent = code;
+	const classString = "class";
+	bool foundPossibleClass;
+	bool foundClass;
+	string[] classNames;
+	string className;
+	
+	for (size_t i = 0; i < fileContent.length; i++)
+	{		
+		final c = fileContent[i];
+		
+		if (foundPossibleClass)
+		{
+			if (c == ' ' || c == '\n')
+				foundClass = true;
+			
+			foundPossibleClass = false;
+		}
+		
+		else if (foundClass)
+		{			
+			if (c == '{')
+			{
+				classNames ~= className;
+				foundClass = false;
+				className = "";
+			}
+			
+			else if (c != ' ' && c != '\n')
+				className ~= c;
+		}
+		
+		else
+		{
+			if (i + classString.length < fileContent.length)
+			{
+				if (fileContent[i .. i + classString.length] == classString)
+				{
+					if (i > 0)
+					{
+						if (fileContent[i - 1] == ' ' || fileContent[i - 1] == '\n' || fileContent[i - 1] == ';' || fileContent[i - 1] == '}')
+						{
+							foundPossibleClass = true;
+							i += classString.length - 1;
+							continue;
+						}
+					}
+					
+					else
+					{
+						foundPossibleClass = true;
+						i += classString.length - 1;
+						continue;
+					}
+				}
+			}
+		}
+	}
+	
+	return classNames;
+}
+
+/**
+ * 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, 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);
+}
+
+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