C#: PG required, obscene case fall through code and Duff device
I had said before that I miss case fall through in C# and I promised that I'd write about some weird uses of this feature in C++.
I think the weirdest use of case statement was made by Tom Duff. He needed to write some code in C that copied an array of shorts into a pre-programmed IO data register. The code looked like
void loopSend(register short* to, register short* from, register int count){ do *to = *from++; while(--count > 0);}
The compiler emitted instructions to compare the count with zero after each copying each short. This had a considerable perf hit and so he decided to apply common loop unrolling technique. This is where things became extremely weird. He used a little-known C feature in which switch-case statements can be inter-leaved with other statements. The optimized code looked like
void send(register short *to, register short *from, register int count){ register int n=(count+7)/8; switch(count%8){ case 0: do{ *to = *from++; case 7: *to = *from++; case 6: *to = *from++; case 5: *to = *from++; case 4: *to = *from++; case 3: *to = *from++; case 2: *to = *from++; case 1: *to = *from++; }while(--n>0); }}
If you are wondering if its legal C, then think again, as this is not only legal C, it's legal C++ as well. If you change all *to to *to++ this becomes a memcpy code which is more relevant to most programmers. When I first saw this is college, I had to actually step through the code to figure out how it worked and then kept wondering why there was no obscene code warning before the code and so I made it a point to add it in the blog title :)
Some people took this to the extreme and created a stack based co-routine. People who take yield return for granted should try understanding the following
#define crBegin static int state=0; switch(state) { case 0:#define yieldReturn(i,x) do { state=i; return x; case i:; } while (0)#define crFinish }int function(void) { static int i; crBegin; for (i = 0; i < 10; i++) yieldReturn(1, i); crFinish;}
Comments
- Anonymous
November 23, 2005
I'm afraid this won't compile in C. case labels require a constant. Nice try, though. - Anonymous
November 23, 2005
Worst code ever. That is over-optimised and un-maintainable. I'd prefer a slow solution to THAT solution. :-| - Anonymous
November 23, 2005
The comment has been removed - Anonymous
November 23, 2005
Evin I said the first sample (Duff device) is legal C. The coroutine is C++. - Anonymous
November 23, 2005
Manip what kfarmer highlights is absolutely true. The original Duff device was coded to handle a bottle neck that was slowing down an animation payback. If some situation you just cannot do without such things. Since I was an embedded system programmer for some time, I wrote lots of code that used loop un-rolling to speed up that MP3 ringtone play-back on your cell phone :) - Anonymous
November 23, 2005
The case label is constant -- it's a preprocessor substitution, not a source variable.
Google has Tom Duff's original post archived, FWIW:
http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c