Mercurial > projects > mde
diff mde/mergetag/DefaultData.d @ 14:0047b364b6d9
Changed much of the mergetag structure and some functionality. First tests on windows.
Changes to mergetag Reader methods. New functionality allowing a dataSecCreator to cause sections to be skipped.
Moved several of the mergetag modules and some of their contents around. Moved all interfaces to separate modules in iface/ .
IReader & IWriter interfaces exist; MTTReader, MTBReader, MTTWriter, MTBWriter & DualWriter all now exist and implement IReader/IWriter (although the MTB variants are dummy classes); makeReader & makeWriter should both be fully functional.
Tested building on windows with partial success (works but window won't open).
Included a temporary hack from windows to get supported resolutions information.
committer: Diggory Hardy <diggory.hardy@gmail.com>
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Fri, 07 Mar 2008 17:51:02 +0000 |
parents | |
children | 5f90774ea1ef |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mde/mergetag/DefaultData.d Fri Mar 07 17:51:02 2008 +0000 @@ -0,0 +1,163 @@ +/** This module contains the DefaultData class, and some notes possibly useful for implementing +* other types of DataSection. +*/ +module mde.mergetag.DefaultData; + +public import mde.mergetag.iface.IDataSection; +import mde.mergetag.exception; + +import tango.scrapple.text.convert.parseTo : parseTo; +import tango.scrapple.text.convert.parseFrom : parseFrom; + + +/** +* Default DataSection class. +* +* Supports most of the basic types supported by D (excluding cent/ucent and imaginary/complex +* types) and array versions of each of these types, plus arrays of strings. +* +* Extending the class to support more types, even custom types, shouldn't be particularly difficult +* provided mde.text.parseTo and mde.text.parseFrom are extended to support the new types. +*/ +/* The implementation now uses a fair bit of generic programming. Adjusting the types supported +* should be as simple as adjusting the list dataTypes, and possibly implemting new conversions in +* parseFrom and parseTo if you add new types (e.g. for cent or imaginary/complex types, or user types). +* +* There shouldn't really be any need to adjust the implementation, except perhaps to add new +* functions to the class (such as another type of output where the delegate used in writeAll isn't +* enough). +*/ +class DefaultData : IDataSection +{ + //BEGIN META + /* These functions are used to generate code. Compile-time functions rather than templates are + * used because they are easier to write and understand. Mixins are used to compile the resultant + * code. Must be declared before used since forward references aren't supported for compile-time + * functions. */ + + // Generate the correct name for each variable type. + static char[] varName (char[] type) { + char[] append = ""; + while (type.length >= 2 && type[$-2..$] == "[]") { + type = type[0..$-2]; + append ~= "A"; + } + return "_" ~ type ~ append; + } + + // Int-to-string converter, which may not be efficient but will run at compile time. + static char[] int2str (uint i) { + char[] ret; + const digits = "0123456789"; + if (i == 0) ret = "0"; + else for (; i > 0; i /= 10) ret = digits[i%10] ~ ret; + return ret; + } + + // Generate the code for variable declarations. + static char[] declerations (char[][] types) { + char[] ret = ""; + foreach (char[] type; types) ret ~= type ~ "[ID]\t" ~ varName(type) ~ ";\n"; + return ret; + } + + // Purely to add indentation. Could just return "" without affecting functionality. + static char[] indent (uint i) { + char[] ret; + for (; i > 0; --i) ret ~= " "; + // This is not executable at compile time: + //ret.length = i * 4; // number of characters for each indentation + //ret[] = ' '; // character to indent with + return ret; + } + + /* Generates a binary search algorithm. + * + * Currently this is tailored to it's particular use (addTag). */ + static char[] binarySearch (char[] var, char[][] consts, int indents = 0) { + if (consts.length > 3) { + return indent(indents) ~ "if (" ~ var ~ " <= \"" ~ consts[$/2 - 1] ~ "\") {\n" ~ + binarySearch (var, consts[0 .. $/2], indents + 1) ~ + indent(indents) ~ "} else {\n" ~ + binarySearch (var, consts[$/2 .. $], indents + 1) ~ + indent(indents) ~ "}\n"; + } else { + char[] ret; + ret ~= indent(indents); + foreach (c; consts) { + ret ~= "if (" ~ var ~ " == \"" ~ c ~ "\") {\n" ~ + indent(indents+1) ~ varName(c) ~ "[id] = parseTo!(" ~ c ~ ") (dt);\n" ~ + indent(indents) ~ "} else "; + } + ret = ret[0..$-6] ~ '\n'; // remove last else + return ret; + } + } + + // Generates the code to write data members (writeAll). + static char[] writeVars () { + char[] code = ""; + foreach (i,type; dataTypes) { + code ~= "foreach (id, dt; " ~ varName(type) ~ ") itemdlg (dataTypes[" ~ int2str(i) ~ "], id, parseFrom!(" ~ type ~ ")(dt));\n"; + } + return code; + } + //END META + + /** Data Members + * + * These types are all stored directly, as below, are available for direct access. The variable + * names are created dynamically at compile-time based on the dataTypes list. + * ------------------ + * int[ID] _int; // name is type prefixed by _ + * char[][ID] _charA; // [] is replaced by A + * ------------------ + * + * An alternative access method is to use the provided templates: + * -------------------- + * template Arg(T) { + * alias Name Arg; + * } + * + * type y = Arg!(type).Arg; // example of use + * -------------------- + * Note: trying to use Arg!(type) to implicitly refer to Arg!(type).Arg causes compiler errors + * due to the "alias Name Arg;" statement actually being a mixin. + */ + const char[][] dataTypes = ["bool","bool[]", + "byte","byte[]", + "char","char[]","char[][]", + "double","double[]", + "float","float[]", + "int","int[]", + "long","long[]", + "real","real[]", + "short","short[]", + "ubyte","ubyte[]", + "uint","uint[]", + "ulong","ulong[]", + "ushort","ushort[]"]; + + mixin (declerations (dataTypes)); // Declare all the variables. + + void addTag (char[] type, ID id, char[] dt) { /// Supports all types listed in dataTypes. + mixin (binarySearch ("type", dataTypes)); + } + + void writeAll (ItemDelg itemdlg) { /// Supports all types listed in dataTypes. + mixin (writeVars ()); + } + + /* These make no attempt to check Arg is valid. + * But if the symbol doesn't exist the complier will throw an error anyway, e.g.: + * Error: identifier '_boolAA' is not defined + */ + template Arg(T : T[]) { + const ArgString = Arg!(T).ArgString ~ `A`; + mixin(`alias `~ArgString~` Arg;`); + } + template Arg(T) { + const ArgString = `_` ~ T.stringof; + mixin(`alias `~ArgString~` Arg;`); + } +}