Index: tango/text/convert/Layout.d =================================================================== --- tango/text/convert/Layout.d (revision 3533) +++ tango/text/convert/Layout.d (working copy) @@ -39,18 +39,31 @@ *******************************************************************************/ -version (GNU) - { - private import std.stdarg; - alias void* Arg; - alias va_list ArgList; - } - else - { - alias void* Arg; - alias void* ArgList; - } +alias void* Arg; +alias void*[] ArgList; +template Nargs(){ + const int Nargs=0; +} +template Nargs(T,U...){ + const int Nargs=1+Nargs!(U); +} +template isArray(T) +{ + static if( is( T U : U[] ) ) + const isArray = true; + else + const isArray = false; +} + +template isStaticArray(T) +{ + static if( is( typeof(T.init)[(T).sizeof / typeof(T.init).sizeof] == T ) ) + const isStaticArray = true; + else + const isStaticArray = false; +} + /******************************************************************************* Contains methods for replacing format items in a string with string @@ -60,18 +73,41 @@ class Layout(T) { - public alias convert opCall; public alias uint delegate (T[]) Sink; + private template resultConvert(V){ + static if(is(V==Sink)){ + alias uint resultConvert; + } else { + static if (isStaticArray!(V)) + alias typeof(V.dup) resultConvert; + else + alias V resultConvert; + } + } + resultConvert!(V) opCall(V,U...)(V x,U args){ + static if (is(V==Sink)) { + return convertSink(x,args); + } else { + return convert(x,args); + } + } + /********************************************************************** **********************************************************************/ - - public final T[] sprint (T[] result, T[] formatStr, ...) - { - return vprint (result, formatStr, _arguments, _argptr); + public T[] sprint(U...)(T[] result, T[] formatStr,U args){ + const int nargs=Nargs!(U); + void *[nargs] aPtrs; + TypeInfo[nargs] aTis; + foreach(i,a;args){ + aPtrs[i]=cast(void*)&a; + aTis[i]=typeid(U[i]); + } + TypeInfo[] aTisDyn=aTis; + ArgList aPtrsDyn=aPtrs; + return vprint(result,formatStr,aTisDyn,aPtrsDyn); } - /********************************************************************** **********************************************************************/ @@ -93,7 +129,7 @@ return len; } - convert (&sink, arguments, args, formatStr); + convertSink (&sink, arguments, args, formatStr); return result [0 .. p-result.ptr]; } @@ -130,39 +166,98 @@ will be:$(BR) "99 bottles of beer on the wall". **********************************************************************/ + public uint convertSink(V,U...)(Sink sink,V x,U args){ + const int nargs=Nargs!(U); + static if (is(V:T[])) { + void *[nargs] aPtrs; + TypeInfo[nargs] aTis; + char [][nargs] cstr; + wchar[][nargs] wstr; + dchar[][nargs] dstr; + foreach (i,argT;U){ + static if (isStaticArray!(argT) && (is(argT:char[])||is(argT:wchar[])||is(argT:dchar[]))){ + static if (is(argT:char[])){ + cstr[i]=args[i]; + aPtrs[i]=cast(void*)&cstr[i]; + } else static if (is(argT:wchar[])){ + wstr[i]=args[i]; + aPtrs[i]=cast(void*)&wstr[i]; + } else static if (is(argT:dchar[])){ + dstr[i]=args[i]; + aPtrs[i]=cast(void*)&dstr[i]; + } + aTis[i]=typeid(typeof(argT.dup)); + } else { + aTis[i]=typeid(argT); + aPtrs[i]=cast(void*)&args[i]; + } + } + void *[] aPtrsDyn=aPtrs; + TypeInfo[] aTisDyn=aTis; + return parse(x,aTisDyn,aPtrsDyn,sink); + } else { + static assert(nargs==2,"invalid number of arguments "); + static if (!(is(V:TypeInfo[]) && is(U[0]:ArgList) && is(U[1]:T[]))){ + return "a"+"b"; // make the compiler complain + } + // static assert(is(V:TypeInfo[]) && is(U[0]:ArgList) && is(U[1]:T[]),"invalid argument types"); + void *[] aPtrsDyn=args[0]; + TypeInfo[] aTisDyn=x; + return parse (args[1], aTisDyn, aPtrsDyn, sink); + } + } + public T[] convert(V,U...)(V x, U args){ + const int nargs=Nargs!(U); + static if(is(V:T[])){ + void *[nargs] aPtrs; + TypeInfo[nargs] aTis; + char [][nargs] cstr; + wchar[][nargs] wstr; + dchar[][nargs] dstr; + foreach (i,argT;U){ + aPtrs[i]=cast(void*)&args[i]; + static if (isStaticArray!(argT) && (is(argT:char[])||is(argT:wchar[])||is(argT:dchar[]))){ + static if (is(argT:char[])){ + cstr[i]=args[i]; + aPtrs[i]=cast(void*)&cstr[i]; + } else static if (is(argT:wchar[])){ + wstr[i]=args[i]; + aPtrs[i]=cast(void*)&wstr[i]; + } else static if (is(argT:dchar[])){ + dstr[i]=args[i]; + aPtrs[i]=cast(void*)&dstr[i]; + } + aTis[i]=typeid(typeof(argT.dup)); + } else { + aTis[i]=typeid(argT); + aPtrs[i]=cast(void*)&args[i]; + } + } + + return convert (aTis, aPtrs, x); + } else static if (is(V:TypeInfo[])){ + static assert(nargs==2); + static assert(is(U[0]:ArgList) && is(U[1]:T[])); + T[] output; - public final T[] convert (T[] formatStr, ...) - { - return convert (_arguments, _argptr, formatStr); - } - - /********************************************************************** - - **********************************************************************/ - - public final uint convert (Sink sink, T[] formatStr, ...) - { - return convert (sink, _arguments, _argptr, formatStr); - } - - /********************************************************************** - - **********************************************************************/ - - public final T[] convert (TypeInfo[] arguments, ArgList args, T[] formatStr) - { - T[] output; - - uint sink (T[] s) - { - output ~= s; - return s.length; + uint sink (T[] s) + { + output ~= s; + return s.length; + } + + convertSink (&sink, x, args[0], args[1]); + return output; + } else static if (is(V==Sink)) { + pragma(msg,"use convertSink for this call"); + // static assert(0,"use convertSink"); + return 15.6L; // make the compiler complain and give us a better error than static assert + } else { + pragma(msg,"Unexpected first argument to convert: "~V.stringof); + static assert(0,"Unexpected first argument"); } + } - convert (&sink, arguments, args, formatStr); - return output; - } - /********************************************************************** **********************************************************************/ @@ -174,102 +269,6 @@ /********************************************************************** - **********************************************************************/ - - public final uint convert (Sink sink, TypeInfo[] arguments, ArgList args, T[] formatStr) - { - assert (formatStr, "null format specifier"); - assert (arguments.length < 64, "too many args in Layout.convert"); - - version (GNU) - { - Arg[64] arglist = void; - int[64] intargs = void; - byte[64] byteargs = void; - long[64] longargs = void; - short[64] shortargs = void; - void[][64] voidargs = void; - real[64] realargs = void; - float[64] floatargs = void; - double[64] doubleargs = void; - - foreach (i, arg; arguments) - { - static if (is(typeof(args.ptr))) - arglist[i] = args.ptr; - else - arglist[i] = args; - /* Since floating point types don't live on - * the stack, they must be accessed by the - * correct type. */ - bool converted = false; - switch (arg.classinfo.name[9]) - { - case TypeCode.FLOAT: - floatargs[i] = va_arg!(float)(args); - arglist[i] = &floatargs[i]; - converted = true; - break; - - case TypeCode.DOUBLE: - doubleargs[i] = va_arg!(double)(args); - arglist[i] = &doubleargs[i]; - converted = true; - break; - - case TypeCode.REAL: - realargs[i] = va_arg!(real)(args); - arglist[i] = &realargs[i]; - converted = true; - break; - - default: - break; - } - if (! converted) - { - switch (arg.tsize) - { - case 1: - byteargs[i] = va_arg!(byte)(args); - arglist[i] = &byteargs[i]; - break; - case 2: - shortargs[i] = va_arg!(short)(args); - arglist[i] = &shortargs[i]; - break; - case 4: - intargs[i] = va_arg!(int)(args); - arglist[i] = &intargs[i]; - break; - case 8: - longargs[i] = va_arg!(long)(args); - arglist[i] = &longargs[i]; - break; - case 16: - voidargs[i] = va_arg!(void[])(args); - arglist[i] = &voidargs[i]; - break; - default: - assert (false, "Unknown size: " ~ Integer.toString (arg.tsize)); - } - } - } - } - else - { - Arg[64] arglist = void; - foreach (i, arg; arguments) - { - arglist[i] = args; - args += (arg.tsize + int.sizeof - 1) & ~ (int.sizeof - 1); - } - } - return parse (formatStr, arguments, arglist, sink); - } - - /********************************************************************** - Parse the format-string, emitting formatted args and text fragments as we go. @@ -389,7 +388,7 @@ // an astonishing number of typehacks needed to handle arrays :( void processElement (TypeInfo _ti, Arg _arg) { - if (_ti.classinfo.name.length is 20 && _ti.classinfo.name[9..$] == "StaticArray" ) + if (_ti.classinfo.name.length is 20 && _ti.classinfo.name[9..$] == "StaticArray") { auto tiStat = cast(TypeInfo_StaticArray)_ti; auto p = _arg; @@ -815,7 +814,8 @@ assert( Formatter( "d{{0}d", "" ) == "d{0}d"); assert( Formatter( "d{{{0}d", "" ) == "d{d"); assert( Formatter( "d{0}}d", "" ) == "d}d"); - + assert( Formatter( "{} {} {} {} {:x}",1.3f,cast(bool)1,1.4,cast(bool)1, 0xafe0000 ) == "1.30 true 1.40 true afe0000" ); + assert( Formatter( "{} {} {} {} {:x}",0.0f,cast(bool)1,0.0,cast(bool)1, 0xafe0000 ) == "0.00 true 0.00 true afe0000" ); assert( Formatter( "{0:x}", 0xafe0000 ) == "afe0000" ); // todo: is it correct to print 7 instead of 6 chars??? assert( Formatter( "{0:x7}", 0xafe0000 ) == "afe0000" ); @@ -891,6 +891,7 @@ assert( Formatter( "{:x}", a ) == "[ 33, 34, 35, 36, 37 ]" ); assert( Formatter( "{,-4}", a ) == "[ 51 , 52 , 53 , 54 , 55 ]" ); assert( Formatter( "{,4}", a ) == "[ 51, 52, 53, 54, 55 ]" ); + assert( Formatter( "{} {}", a,cast(byte)21 ) == "[ 51, 52, 53, 54, 55 ] 21" ); int[][] b = [ [ 51, 52 ], [ 53, 54, 55 ] ]; assert( Formatter( "{}", b ) == "[ [ 51, 52 ], [ 53, 54, 55 ] ]" ); @@ -911,6 +912,8 @@ f[ 1.0 ] = "one".dup; f[ 3.14 ] = "PI".dup; assert( Formatter( "{}", f ) == "{ 1.00=>one, 3.14=>PI }" ); + + } } Index: tango/text/convert/Sprint.d =================================================================== --- tango/text/convert/Sprint.d (revision 3533) +++ tango/text/convert/Sprint.d (working copy) @@ -92,20 +92,13 @@ **********************************************************************/ - T[] format (T[] fmt, ...) + T[] format(S...) (T[] fmt,S args) { - return layout.vprint (buffer, fmt, _arguments, _argptr); + static if(is(S[0]:TypeInfo[])){ + assert(is(S[1]:ArgList)); + } + return layout.sprint (buffer, fmt, args); } - /********************************************************************** - - Layout a set of arguments - - **********************************************************************/ - - T[] format (T[] fmt, TypeInfo[] arguments, ArgList argptr) - { - return layout.vprint (buffer, fmt, arguments, argptr); - } } Index: tango/io/stream/SnoopStream.d =================================================================== --- tango/io/stream/SnoopStream.d (revision 3533) +++ tango/io/stream/SnoopStream.d (working copy) @@ -132,10 +132,10 @@ ***********************************************************************/ - private void trace (char[] format, ...) + private void trace(S...) (char[] format, S args) { char[256] tmp = void; - snoop (Format.vprint (tmp, format, _arguments, _argptr)); + snoop (Format.sprint (tmp, format, args)); } } @@ -249,10 +249,10 @@ ***********************************************************************/ - private void trace (char[] format, ...) + private void trace(S...) (char[] format,S args) { char[256] tmp = void; - snoop (Format.vprint (tmp, format, _arguments, _argptr)); + snoop (Format.sprint (tmp, format, args)); } } Index: tango/io/Print.d =================================================================== --- tango/io/Print.d (revision 3533) +++ tango/io/Print.d (working copy) @@ -123,9 +123,9 @@ **********************************************************************/ - final Print format (T[] fmt, ...) + final Print format(S...) (T[] fmt, S args) { - convert (&sink, _arguments, _argptr, fmt); + convertSink (&sink, fmt, args); return this; } @@ -135,9 +135,9 @@ **********************************************************************/ - final Print formatln (T[] fmt, ...) + final Print formatln(S...) (T[] fmt, S args) { - convert (&sink, _arguments, _argptr, fmt); + convertSink (&sink, fmt, args); return newline; } @@ -147,20 +147,30 @@ Currently supports a maximum of 24 arguments **********************************************************************/ - - final Print print (...) + template Nargs(){ + const int Nargs=0; + } + template Nargs(T,U...){ + const int Nargs=1+Nargs!(U); + } + T[] sliceStr(int nArgs){ + char[] res="".dup; + for (int i=0;i