# HG changeset patch # User Saaa # Date 1254918327 -7200 # Node ID c5a9d253bfd4f1566c889b36af539aaa4cd39ff4 # Parent 8e3ddf7a317896810400b2d003ecc2b7e3c5546d moving to correct folder diff -r 8e3ddf7a3178 -r c5a9d253bfd4 ddata/ddata.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ddata/ddata.d Wed Oct 07 14:25:27 2009 +0200 @@ -0,0 +1,283 @@ +module ddata.ddata; + +//debug +//import std.stdio; +import std.string; + +import std2.conv : to; +import std2.traits : isNumeric; + +class DDataException : Exception +{ + this(char[] msg) + { + super(msg); + } + this( uint loc, char c, char[] msg) + { + super( format( `parsing failed at string[`, loc-1, `] = '`,c,`'` ,msg)); + } +} + + +private enum TOKEN{ BOF, SQUARE_L, SQUARE_R, COMMA, ECOMMA, VALUE, EOF} + +private template Depth(T: T[]) { const Depth = 1 + Depth!(T); } +private template Depth(T) { const Depth = 0; } + +private template BaseType(T: T[]) { alias BaseType!(T) BaseType; } +private template BaseType(T) { alias T BaseType; } + +private template indexAssign(T: T[]) +{ + void indexAssign(ref T array, BaseType!(T) value, int[] indices) + { + static if( is( typeof(array[0]) == typeof(value))) + { + array[indices[0]] = value; + } + else + { + indexAssign!(T)( array[indices[0]], value, indices[1..$]); + } + } +} + +private string ctToString(int i) +{ + if (!i) return "0"; + string res; + while (i) { + res = "0123456789"[i%10] ~ res; + i /= 10; + } + return res; +} + +private string indexString(int len) +{ + string res; + for (int i = 0; i < len; ++i) + res ~= "[index["~ctToString(i)~"]] "; + return res; +} + +private string casesString(int depth, TOKEN type) +{ + string res; + res ~= `switch( depth ){`; + + for (int i = 0; i < depth; ++i) + { + switch(type) + { + case TOKEN.COMMA: + res ~=`case `~ctToString(i)~`:`~ + `if(temp`~ indexString(i) ~`.length<=index[`~ctToString(i)~`] )temp`~ indexString(i) ~`.length=temp`~ indexString(i) ~`.length*2;`~ + `break;`; + break; + + case TOKEN.SQUARE_L: + res ~=`case `~ctToString(i)~`:`~ + `temp`~ indexString(i) ~`.length=4;`~ + `break;`; + break; + + case TOKEN.SQUARE_R: + res ~=`case `~ctToString(i)~`:`~ + `temp`~ indexString(i) ~`.length=index[`~ctToString(i)~`];`~ + `break;`; + break; + + default: + assert(false); + break; + } + } + + res ~= `default:assert(false);break;}`; + return res; +} + + +bool toBool(char[] s) +{ + if(s == `true`) + { + return true; + } + else if(s == `false`) + { + return false; + } + else + { + throw new Exception(`Cannot convert "`~s~`" to bool`); + } + return false; +} + +public T toArray(T:D[],D)(char[] string) +{ + int[ Depth!(T) ] index = 0; + + T temp; + char c; + + int depth = -1; + + int sLoc1 = -1, sLoc2 = -1; + int loc = -1; + + TOKEN last = TOKEN.BOF; + + while(true) + { + loc++; + //debug + //writefln(loc); + if( loc >= string.length ) + { + if( last != TOKEN.SQUARE_R) throw new DDataException( `unexpected end`); + if( depth != -1 ) throw new DDataException( `array depth not zero after parsing `); + //throw new DDataException(`EOF before end of parsing`); + return temp; + } + + c = string[loc]; + //debug + //writefln(c); + switch(c) + { + case ' ', '\t', '\v', '\r', '\n', '\f': + if( last == TOKEN.ECOMMA || last == TOKEN.SQUARE_L) + { + if(sLoc2 < 0) + { + sLoc1 = loc + 1; + }else{ + sLoc2 = loc; + last = TOKEN.VALUE; + } + } + break; + + case ',': + index[depth] ++; + + // resize array if necessary + mixin ( casesString(Depth!(T), TOKEN.COMMA ) ); + + if( last == TOKEN.VALUE && depth == Depth!(T)-1 ) + { + index[depth] --; + static if( is(BaseType!(T) == bool) ) + { + indexAssign!(T[])( temp, toBool( string[ sLoc1..sLoc2] ), index); + } + else static if( isNumeric!( BaseType!(T) ) ) + { + indexAssign!(T[])( temp, to!( BaseType!(T) )( string[ sLoc1..sLoc2] ), index); + } + else + { + assert(false); + } + index[depth] ++; + sLoc1 = -1; + sLoc2 = -1; + last = TOKEN.ECOMMA; + }else if( last == TOKEN.SQUARE_R ){ + last = TOKEN.COMMA; + }else{ + throw new DDataException( loc, c, `: Value, ']' or ',' expected.`); + } + break; + + case '[': + if( last != TOKEN.COMMA && last != TOKEN.BOF && last != TOKEN.SQUARE_L ) throw new DDataException( loc, c, `: Beginning, '[' or ',' expected.`); + + depth++; + if(depth > index.length) throw new DDataException( loc, c, `: Array too deep = `~toString(depth)); + mixin ( casesString(Depth!(T), TOKEN.SQUARE_L ) ); + index[depth] = 0; + last = TOKEN.SQUARE_L; + sLoc1 = -1; + sLoc2 = -1; + break; + + case ']': + if( last == TOKEN.VALUE && depth == Depth!(T)-1 && sLoc2 != -1) + { + static if( is(BaseType!(T) == bool) ) + { + indexAssign!(T[])( temp, toBool( string[ sLoc1..sLoc2]), index); + } + else static if( isNumeric!( BaseType!(T) ) ) + { + indexAssign!(T[])( temp, to!( BaseType!(T) )(string[ sLoc1..sLoc2]), index); + } + else + { + assert(false); + } + sLoc1 = -1; + sLoc2 = -1; + index[depth] ++; + } + else if( last == TOKEN.SQUARE_L ) + { + sLoc1 = -1; + sLoc2 = -1; + } + else if( last == TOKEN.SQUARE_R) + { + index[depth] ++; + } + else + { + throw new DDataException( loc, c, `: Value, '[' or ']' expected.`); + } + + // set array length to index[depth] + mixin ( casesString(Depth!(T), TOKEN.SQUARE_R) ); + + index[depth] = 0; + depth--; + last = TOKEN.SQUARE_R; + break; + + default: + if( last == TOKEN.ECOMMA || last == TOKEN.SQUARE_L || last == TOKEN.VALUE) + { + if( sLoc1 < 0 ) + { + sLoc1 = loc; + sLoc2 = loc +1; + } else { + sLoc2 = loc +1; + } + last = TOKEN.VALUE; + break; + } + throw new DDataException( loc, c, `: Out of place char found `); + break; + } + } +} + +unittest +{ + writefln("DData UnitTest..."); + + int[][][] ia = [ [[1,2],[3,4],[5]] , [[6],[],[7,8,9]] , [[]] ]; + + char[] s = to!(char[])(ia); + int[][][] ia2; + + ia2 = toArray!(typeof(ia2))(s); + assert( ia == ia2); + + writefln("Done!"); +} +