Connecting Tech Pros Worldwide Forums | Help | Site Map

Why does it work?

Ruben Campos
Guest
 
Posts: n/a
#1: Dec 30 '05
Greetings.

I was recently reading the article "Typed buffers (II)", by Andrei
Alexandrescu (C/C++ Users Journal, October 2001), and I found the next
function in it:

template <class T> inline void FillDuff
(T* begin, T* end, const T& obj)
{
switch ((end - begin) & 7)
{
case 0:
while (begin != end)
{
*begin = obj; ++begin;
case 7: *begin = obj; ++begin;
case 6: *begin = obj; ++begin;
case 5: *begin = obj; ++begin;
case 4: *begin = obj; ++begin;
case 3: *begin = obj; ++begin;
case 2: *begin = obj; ++begin;
case 1: *begin = obj; ++begin;
}
}
}

After reading Andrei's explanation and analyzing the code for a while, I
understood the way it works. Also, I tried it in order to see it myself,
and everything was right. But I still do not understand why that code
even compiles, so I would be very grateful if someone could throw some
light.

From my point of view, when the execution thread initially reaches the
"switch" sentence the remainder is computed, and a jump is performed to
the corresponding "case". Being the remainder not null, why is the
"while" sentence executed? Tracing with MSVC 7.1 shows the expected jump
from "switch" directly to the corresponding "case" line, without
evaluating the "while" condition. But after executing until the last
case, it reaches the "while" closing bracket and then jumps back to
continue with the "while" loop. Until now, I believed the only way to
enter a "while" loop was through its initial "while" sentence.

I supposed this could be discussed when published, so I apologize if
coming back again over an already treated matter. Thank you in advance.

Rubén Campos

Mike Wahler
Guest
 
Posts: n/a
#2: Dec 30 '05

re: Why does it work?



"Ruben Campos" <ruben.campos@glup.irobot.uv.es> wrote in message
news:dp3i1g$dvv$1@peque.uv.es...[color=blue]
> Greetings.
>
> I was recently reading the article "Typed buffers (II)", by Andrei
> Alexandrescu (C/C++ Users Journal, October 2001), and I found the next
> function in it:
>
> template <class T> inline void FillDuff
> (T* begin, T* end, const T& obj)
> {
> switch ((end - begin) & 7)
> {
> case 0:
> while (begin != end)
> {
> *begin = obj; ++begin;
> case 7: *begin = obj; ++begin;
> case 6: *begin = obj; ++begin;
> case 5: *begin = obj; ++begin;
> case 4: *begin = obj; ++begin;
> case 3: *begin = obj; ++begin;
> case 2: *begin = obj; ++begin;
> case 1: *begin = obj; ++begin;
> }
> }
> }
>
> After reading Andrei's explanation and analyzing the code for a while, I
> understood the way it works. Also, I tried it in order to see it myself,
> and everything was right. But I still do not understand why that code even
> compiles, so I would be very grateful if someone could throw some light.
>
> From my point of view, when the execution thread initially reaches the
> "switch" sentence the remainder is computed, and a jump is performed to
> the corresponding "case". Being the remainder not null, why is the "while"
> sentence executed? Tracing with MSVC 7.1 shows the expected jump from
> "switch" directly to the corresponding "case" line, without evaluating the
> "while" condition. But after executing until the last case, it reaches the
> "while" closing bracket and then jumps back to continue with the "while"
> loop. Until now, I believed the only way to enter a "while" loop was
> through its initial "while" sentence.
>
> I supposed this could be discussed when published, so I apologize if
> coming back again over an already treated matter. Thank you in advance.[/color]

This has indeed been discussed at great length by
some folks, but mostly in a C context, so using
only C++, you might or might not have heard of
"Duff's Device":

http://www.lysator.liu.se/c/duffs-device.html

-Mike


AD
Guest
 
Posts: n/a
#3: Dec 30 '05

re: Why does it work?


Another interesting read :
http://pera-software.com/articles/duff-device.pdf

Roberto Waltman
Guest
 
Posts: n/a
#4: Dec 30 '05

re: Why does it work?


<ruben.campos@glup.irobot.uv.es> wrote:[color=blue]
>I was recently reading the article "Typed buffers (II)", by Andrei
>Alexandrescu (C/C++ Users Journal, October 2001), and I found the next
>function in it:
>
>template <class T> inline void FillDuff
> (T* begin, T* end, const T& obj)
>{
> switch ((end - begin) & 7)
> {
> case 0:
> while (begin != end)
> {
> *begin = obj; ++begin;
> case 7: *begin = obj; ++begin;
> case 6: *begin = obj; ++begin;
> case 5: *begin = obj; ++begin;
> case 4: *begin = obj; ++begin;
> case 3: *begin = obj; ++begin;
> case 2: *begin = obj; ++begin;
> case 1: *begin = obj; ++begin;
> }
> }
>}
>
>After reading Andrei's explanation and analyzing the code for a while, I
>understood the way it works. Also, I tried it in order to see it myself,
>and everything was right. But I still do not understand why that code
>even compiles, so I would be very grateful if someone could throw some
>light.[/color]

It is a well know idiom (or "trick"?) in the C language.
Search for "Duff's device." I do believe that in an
ideal world that code should not compile, but on this
one that is legal C/C++.

Roberto Waltman

[ Please reply to the group, ]
[ return address is invalid. ]
Ron Natalie
Guest
 
Posts: n/a
#5: Dec 30 '05

re: Why does it work?


Ruben Campos wrote:
[color=blue]
> From my point of view, when the execution thread initially reaches the
> "switch" sentence the remainder is computed, and a jump is performed to
> the corresponding "case". Being the remainder not null, why is the
> "while" sentence executed?[/color]

You can jump into the middle of a while statement and it will
continue to iterate:

goto foo;
while(condition) {
foo:
statement;
}

the only thing you can't do with either switch or goto is jump over
initializations.
Jim Langston
Guest
 
Posts: n/a
#6: Jan 2 '06

re: Why does it work?


"Ruben Campos" <ruben.campos@glup.irobot.uv.es> wrote in message
news:dp3i1g$dvv$1@peque.uv.es...[color=blue]
> Greetings.
>
> I was recently reading the article "Typed buffers (II)", by Andrei
> Alexandrescu (C/C++ Users Journal, October 2001), and I found the next
> function in it:
>
> template <class T> inline void FillDuff
> (T* begin, T* end, const T& obj)
> {
> switch ((end - begin) & 7)
> {
> case 0:
> while (begin != end)
> {
> *begin = obj; ++begin;
> case 7: *begin = obj; ++begin;
> case 6: *begin = obj; ++begin;
> case 5: *begin = obj; ++begin;
> case 4: *begin = obj; ++begin;
> case 3: *begin = obj; ++begin;
> case 2: *begin = obj; ++begin;
> case 1: *begin = obj; ++begin;
> }
> }
> }
>
> After reading Andrei's explanation and analyzing the code for a while, I
> understood the way it works. Also, I tried it in order to see it myself,
> and everything was right. But I still do not understand why that code even
> compiles, so I would be very grateful if someone could throw some light.
>
> From my point of view, when the execution thread initially reaches the
> "switch" sentence the remainder is computed, and a jump is performed to
> the corresponding "case". Being the remainder not null, why is the "while"
> sentence executed? Tracing with MSVC 7.1 shows the expected jump from
> "switch" directly to the corresponding "case" line, without evaluating the
> "while" condition. But after executing until the last case, it reaches the
> "while" closing bracket and then jumps back to continue with the "while"
> loop. Until now, I believed the only way to enter a "while" loop was
> through its initial "while" sentence.
>
> I supposed this could be discussed when published, so I apologize if
> coming back again over an already treated matter. Thank you in advance.
>
> Rubén Campos[/color]

Because of the way a while statement is translated into assembly. In pseudo
code it would look something like (not exactly and I may be off, just trying
to show the logic).

while ( a != b )
{
// do something
};

would become something like:

:whiletag
compare a, b
if a == b goto end
// do something
goto whiletag
:end

Now, you see if you jump into // do something, the next statement is goto
whiletag which does the compare, etc...





Closed Thread