8/21/2010

08-21-10 - autoprintf

AH HAHA HA ! I think I finally I have the one true printf solution. I can now do :

    autoprintf("hello world\n");
    autoprintf("hello ",7," world\n");
    autoprintf("hello %03d\n",7);
    autoprintf("hello ","world %.1f",3.f,"\n");
    autoprintf("hello %d",3," world %.1f\n",3.f);
    autoprintf("hello ",(size_t)400,"\n");
    autoprintf("hello ",L"unicode is balls"," \n");
    autoprintf("hello ",String("world")," \n");

In particular, all of the following things work :
  • Regular old printf stuff works just like always.

  • .. except that it does type validation against the format string using my old "safeprintf" system

  • You can put args anywhere on the line, not just at the end. This is handy when you get really long printfs going, and makes it easier to copy-paste and rearrange. Similarly you can put format strings anywhere on the line, which is handy when you have a long printf set up and you want to just add something on the end.

  • Does automatic type deduction and output of types that are not explicitly qualified in the format string. In particular a handy one is (size_t) which is not properly supported in a cross-platform way. Any type that doesn't have a % format thingy provided by the caller gets an automatic one.

  • Supports non-basic types in a clean template overriding way. So things like that line that pass a String() as an argument - you will get a compile error if you haven't made a compatible template for that type, or if you have you get nice autoconversion. Basically all the advantages of the C++ iostream << dealy but without the horribleness of having to do your printing that way.

I'm gonna clean up the code a bit and try to extricate it from cblib (meh or maybe not) and I'll post it in a few days.

It does pretty much everything I've always wanted from a printf. There is one thing missing, which is formatting for arbitrary types. Currently you can only format the basic types, and the non-basic types go through a different system. eg. you can either do :

autoprintf("hello %5d ",anInt); 
or
autoprintf("hello ",(size_t)anInt); 
but you can't yet do
autoprintf("hello %5",(size_t)anInt); 
(note that the type specifier is left off, only format specifiers are on the %). I know how to make this work, but it makes the implementation a lot more complicated, so I might punt on it.

The more complicated version is to be able to pass through the format spec into the templated converter. For example, you might have a ToString() for your Vec3 type which makes output like ("{%f,%f,%f}",x,y,z) . With the current system you can do :

Vec3 v;
autoprintf("v = ",v);
and it will call your ToString, but it would be groovy if you could do :
Vec3 v;
autoprintf("v = %.1",v);
as well and have that format apply to the conversion for the type. But that's probably more complication than I want to get into.

Another thing that might be nice is to have an explicit "%a" or something for auto-typed, so you can use them at the end like normal printf args. eg :

autoprintf("hello %d %a %f\n", 3, String("what"), 7.5f );

10 comments:

Julien Koenen said...

Cool stuff, I'm looking forward to seeing the code.

MH said...

Sweet. This looks great.

Anonymous said...

I realize you don't NEED %s, but does %s work or is it incompatible (since it can't tell the difference between a format string and an "argument" string)?

jetro said...

What about order-independent arguments which are handy for L10n?

printf("%s said %s is cool", person1, person2);
might need order of person1 and person2 swapped for some other language.

So in such case it would be handy to have:
printf("%{2}s blabla %{1}s bla", person1, person2);

Apart from missing this, your autoprintf seems very cool! :-D

cbloom said...

" I realize you don't NEED %s, but does %s work or is it incompatible (since it can't tell the difference between a format string and an "argument" string)? "

That mostly works out automatically. There are possible ambiguities, and what I do is look in the string for '%' , so there could be a problem if you are trying to pass a string literal with a % in it, and I treat it as a format string. eg. things like :

autoprintf("tricky %s","yes 100%",7);

MH said...
This comment has been removed by the author.
  said...

sounds good, lets see some code :)

won3d said...

Random question: does this expand your code substantially?

cbloom said...

I'll investigate that. It depends how much I make inline I guess.

BTW I'm gonna support arg reordering partly for that reason. Reordering would require me to generate a template function for each possible reorg, which is N! for N arguments. Way too much code. eg. something like :

U32 reorgCode = GetReorg(formatString);
switch(reorgCode) {
case 0: printf(a1,a2,a3);
case 1: printf(a1,a3,a2);
case 2: printf(a2,a1,a3);
...

no fun.

cbloom said...

"I'm gonna support arg reordering "

->

"I'm *NOT* gonna support arg reordering"

old rants