Thursday, March 13, 2008

Dear all

In past, I have come across many programming tidbits, which inspire and make us a bit better programmers. Thanks to open source software, lot of these gems are lying there, waiting to be unearthed. So come here when you feel like looking at some beautiful code - and wish to reignite that missing sparkle...

Gem 1.

Long time ago, I was reading code of gnu dd. dd has a swab option to swap adjacent bytes...

So given,

abcdefgh

the conv=swab option should give

badcfehg

Now think a moment (imitating Jon Bentley's style ;-), on how you would program this...

Given a null terminated C string, str the function could be written as (C++ version)


char* swab(char* str) {
for (char* p = str; *p; ++p) { /* assertion: skips "" - always moves p */
char* q = p+1; /* assertion - *p != 0 hence q must be within bounds - *q might be 0 */
if (*q) { /* assertion - we only swab non-null chars - as we are here, *p is non-null */
std::swap(*p,*q); /* not shown */
p = q;
}
}
return str;
}

So this is a workable version... (and we can verify it works for corner cases - bugs love corner cases - strings with odd number of chars, no chars, even number of chars... ;-)

That extra squeezing out of performance...
char* swab(char* str) {
char* p = str;
char* q = p-1; /* the caller needs to arrange for this */
while (p[0] && p[1]) { /* invariant - q always trails p by 1 */
*q = q[2];
q += 2;
p += 2;
}
*q = *p;
*p = 0;
return str-1;
}

2 comments:

atul said...

I mean the second version should be called as
char a[] = " xyzt";
swab(&a[1]);
So
q = p-1 is valid...
-- thx atul

atul said...

The second version is loosely based on the original dd code...
--- atul