08-31-10 - LOOP

Every once in a while I think this is a good idea :

#define LOOP(var,count) for(int var=0;(var)<(int)(count);var++)
#define LOOPBACK(var,count) for(int var=(int)(count)-1;(var)>=0;var--)

but then I never wind up using it, and I find the code that does use it looks really ugly. Maybe if I got in the habit that ugliness would go away.

Certainly adding a "loop" keyword would've been a good idea in C99. Instead we have GCC trying to optimize out signed int wrapping, and many compilers now specifically look for the for(;;) construct and special-case handling it as if it was a loop() keyword.

In other minor news, I'm running with the "NoScript" addon now. I've used FlashBlock for a long time to much happiness, so this is just the next level. It does break 90% of web sites out there, but it has also made me shockingly aware of how many random sites are trying to run scripts that are highly questionable (mainly data-mining and ad-serving).

People sometimes ask me about laptops because I wrote about them before :

cbloom rants 05-07-10 - New Lappy
cbloom rants 04-15-10 - Laptop Part 2
cbloom rants 04-12-10 - Laptop search
cbloom rants 01-20-09 - Laptops Part 3

A small update : I'm still very happy with the Dell Precision 6500. They've updated it with some newer GPU options, so you can now get it with an ATI 7820 , which is a full DX11 part and close to as fast as you can get mobile. Other than that all my advice remains the same - get USB 3 of course, quad i7, LED backlighting, install your own SSD and RAM and do a clean windows install. Do NOT get RAID disks, and do NOT install any Intel or Dell drivers. I have no DPC latency problems or any shite like that. The only thing about it that's slightly less than perfect is the temperature / fan control logic is not quite right.

It looks like there's a problem with the NV GTX 280 / Dual chip / Powermizer stuff. See :

My Solution for Dell XPS M1530 DPC Latency
Dell, DPC Latency, and You - Direct2Dell - Direct2Dell - Dell Community
Dell Latitude DPC Latency Issues

So I recommend staying away from that whole family. The new Vaio Z looks really awesome for a small thin/light, however there is a bit of a nasty problem. They only offer it with SSD's in RAID, and they are custom non-replaceable SSD's, and it appears that the reason for the 4 SSD's in RAID is because they are using cheapo low end flash. There's lots of early reports of problems with this setup, and the fact that you have to run RAID and can't change the drives is a big problem. Also, last time I checked Windows still can't send through TRIM to RAID, so that is borked, but theoretically that will be addressed some day.


jeskola said...

I do this pretty often if I have to repeat the same loop several times:

#define LOOP for (int i = 0; i < n; i++)
LOOP x[i] = 123;
LOOP x[i] *= 456;
#undef LOOP

Why not?

Dave Moore said...

So I actually have one of the Z laptops on the way. It appears that the drives have some custom firmware that looks at the NTFS in-use bitmap to do internal trimming. At least that what people have been able to suss out from some very sparse info online. So if you leave the drives formatted as ntfs, you're ok, but if you switch to Linux or a FAT partition, you're screwed.

There's a thread where people have been tracking the write performance of their Zs over time on laptop reviews, iirc. Doesn't seem to be a problem. Hopefully.

won3d said...

C++0x will have a nice thing:


And of course there is this:


but behold the insanity of its implementation!

cbloom said...

"C++0x will have a nice thing:


Well, what do you know! I missed that in the gobs of C++0x spec.

Though "works on any container with begin() end()" is a pretty bananas way to spec it. I would prefer to have a completely generic loop() template which then calls the following scope as if it were a local lambda.

cbloom said...

But the most useful is just an int on a count, because that's the easiest thing for the compiler to tell it can unroll or parallellize or whatever.

Aaron said...

I bet it'd read better as
#define LOOP(var,count) int var=0;(var)<(int)(count);var++

Then code looks like:

for( LOOP(i, 23) )

So it looks like a for loop. It reads like a for loop (literally), and it still has the safety / ease of use of not writing the whole thing out every time.

cbloom said...

"Then code looks like:
for( LOOP(i, 23) )"

Oh yeah that's way better.

In theory you could of course also do things like

#define LOOP_IT(it,cont) cont::iterator it = cont.begin() ...

except that you can't because you can't use a value as a type and there's no typeof() ; (of course you can do this in c++0x)

cbloom said...


for ( LOOP(i,n) )


for LOOP(i,n)


Anonymous said...

> for ( LOOP(i,n) )
> or
> for LOOP(i,n)

I'd vote for ( LOOP(i,n) ) as it enables: for ( LOOP(i,n), ++iterator )

Aaron said...

for ( LOOP(i,n) ) looks more like C

won3d said...

IMO the tiny syntactic win is totally not worth the surprise for new readers of your code, and maybe whatever hidden gotchas, like how often the macro arguments are evaluated.

Too bad about typeof, although it is in GCC already.

cbloom said...

"IMO the tiny syntactic win is totally not worth the surprise for new readers of your code, and maybe whatever hidden gotchas, like how often the macro arguments are evaluated."

Yeah, however, the reality of the RAD codebase is that due to cross-platform fuckitude we basically wind up writing our own meta-language anyway. My code literally looks like this now :

RR_IF_LIKELY( t > 0 )
v[0] + = RR_ROTL32( RR_GET32_BIGENDIAN(k) );

.. etc ..

I don't think LOOP is a very big win, but the fact that I'm running into fucking size_t unsignedness all the time now makes it more compelling.

cbloom said...

I'm definitely very opposed to *local* language redefinition like jeskola's post. If you're going to define your own meta-language, it should at least be static and company-wide.

I know a lot of smart people who have passed around the idea that you should be able to have a meta-language syntax to modify the language locally in a formal way (eg. actually changing the parse tree). I think that is a horrifically bad idea.

And I still think that macros are fucking abominations. In my home code I had almost completely gotten away from them, but now I've been sucked right back in by two huge fuckups :

1. C's failure to support necessary things in the language, which means that compilers have to support them in non-standard ways, which means I use to use macros to get to them with standardize syntax.

2. GCC/PowerPC's fuckup in failing to optimize if you ever call a function or access things through a struct.


won3d said...

Yeah, it looks like the RAD code is working around bad inlining, since it looks like lots of those could be inline functions. In GCC, you'd use attributes like "always_inline" and maybe "artificial."

What's up with RR_IF_LIKELY? As some of your LOOP discussion above hinted at, putting the control flow within the macro is really the nutty thing.

LOOP(...) { ...

is worse than:

for (LOOP(...)) { ...

although I think it is better spelled:

for (RANGE(...)) { ...

Likewise, maybe you should do:

if (RR_LIKELY_THAT(t > 0)) { ...

unless RR_LIKELY_IF contains some really heinous code.

cbloom said...

Mmm, the problem is if you actually want to dynamic hint. RR_IF_LIKELY has to be :

#define RR_IF_LIKELY(expr) \
dynamic_hint(expr,true); \
if ( expr )

if you only want static hinting, then

if ( RR_LIKELY(expr) )

is probably better.

cbloom said...

BTW there's no problem with inline functions (*); most of that could be inline functions.

(*) as long as they actually inline, which means really the only thing that's useful is FORCE-inline functions.

won3d said...

always_inline and __forceinline are about the same. I mean, things aren't that DSL-y if they are really just function calls and whatnot (no control flow, no declrations). But aren't they spelled ALL_CAPS because they are macros? Why not spell them normally? You were using them as a justification for adding more macros, when you clearly want fewer!

What the heck is dynamic_hint?

cbloom said...

Yeah, in practice they are macros but they don't actually need to be, so making them inlines and lower case would be the nicer clean way to go.

The ugliness remains with align and restrict and expect and assume and so on.

And variable types are a total clusterfuck.

won3d said...

What's dynamic_hint?

And another thing. Sure C/C++ macros (really, the entire preprocessor) is an abomination, but I wouldn't necessarily write off better forms of syntactic abstraction.

And really, even without the preprocessor, C++ is a real bear to parse. How many different ways could < be interpreted?

cbloom said...

On the SPU there's no branch predictor, but you can hint a branch manually if you can compute the predicate far enough ahead of the branch.

This probably exists on other deeply pipelined architectures without branch predictors, but the SPU is the only one I know.

old rants