Mercurial > projects > orange
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