Why does it work?

R

Ruben Campos

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
 
M

Mike Wahler

Ruben Campos said:
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.

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
 
R

Roberto Waltman

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.

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. ]
 
R

Ron Natalie

Ruben said:
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?

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.
 
J

Jim Langston

Ruben Campos said:
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

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...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,431
Messages
2,571,679
Members
48,796
Latest member
Greg L.

Latest Threads

Top