[Shootout-list] improved reversefile.c
Alan Post
apost@recalcitrant.org
Wed, 28 Jul 2004 10:15:16 +0000 (UTC)
The following reversefile.c is 10% faster for me for N=20, on my PII
333 NetBSD laptop. It is a translation of the clever ocaml solution,
which avoids copying around the input.
Much less pretty than the ocaml version, of course, because C doesn't
have builtin lists, tuples, pattern matching, type inference, and so
on. :)
/* -*- mode: c -*-
* from Alan Post <apost@recalcitrant.org>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
/*
* Note that malloc(3) seems happier with chunks of 4096
*/
#define MAXREAD (4096 - sizeof( size_t ) - sizeof( void* ))
typedef struct buf_t { char d[MAXREAD];
size_t len;
struct buf_t *next;} buf_t;
static buf_t *read_lines( buf_t *tail )
{
tail->next = NULL;
buf_t *curr = tail;
while ( 1 )
{
int nread = read( STDIN_FILENO, curr->d, MAXREAD );
curr->len = nread;
if ( nread < MAXREAD ) return curr;
buf_t *head = (buf_t*) malloc( sizeof( buf_t ));
head->next = curr;
curr = head;
}
}
#define WRITEOUT \
do { \
fwrite( pos, end - pos, 1, stdout ); \
for (; loh != NULL; loh = loh->next ) \
fwrite( loh->d, loh->len, 1, stdout ); \
} while (0)
int main(int argc, char *argv[]) {
buf_t tail;
buf_t *head = read_lines( &tail );
buf_t *loh = NULL;
buf_t *curr = head;
while ( 1 )
{
char *buf = curr->d;
char *end = buf + curr->len;
char *pos = end;
for (;; pos--)
{
if ( pos <= buf )
{
buf_t *new_curr = curr->next;
if (new_curr == NULL )
{
WRITEOUT;
return(EXIT_SUCCESS);
}
curr->len = end - buf;
curr->next = loh;
loh = curr;
curr = new_curr;
break;
}
if ( *(pos-1) == '\n' )
{
WRITEOUT;
end = pos;
}
}
}
assert( NULL == "unreachable" );
return(EXIT_FAILURE);
}