On Tue, 28 May 2024 23:23:15 +0300
Michael S <
already5chosen@yahoo.com> wrote:
Also, I think that random numbers are close to worst case for branch
predictor / loop length predictor in my inner loop.
Were I thinking about random case upfront, I'd code an inner loop
differently. I'd always copy 4 octets (comma would be stored in the
same table). After that I would update outptr by length taken from
additional table, similarly, but not identically to your method below.
That's what I had in mind:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static const char usage[] =
"bin_to_list - convert binary file to comma-delimited list of decimal
numbers\n" "Usage:\n"
" bin_to_list infile [oufile]\n"
"When output file is not specified, the result is written to standard
output.\n" ;
int main(int argz, char** argv)
{
// process command line
if (argz < 2) {
fprintf(stderr, "%s", usage);
return 1;
}
char* infilename = argv[1];
static const char *help_aliases[] = { "-h", "-H", "-?", "--help",
"--?" }; const int n_help_aliases =
sizeof(help_aliases)/sizeof(help_aliases[0]); for (int i = 0; i <
n_help_aliases; ++i) { if (strcmp(infilename, help_aliases[i])==0) {
fprintf(stderr, "%s", usage);
return 0;
}
}
// open files
FILE* fpin = fopen(infilename, "rb");
if (!fpin) {
perror(infilename);
return 1;
}
FILE* fpout = stdout;
char* outfilename = NULL;
if (argz > 2) {
outfilename = argv[2];
fpout = fopen(outfilename, "w");
if (!fpout) {
perror(outfilename);
fclose(fpin);
return 1;
}
}
enum { MAX_CHAR_PER_LINE = 80, MAX_CHAR_PER_NUM = 4,
ALMOST_FULL_THR = MAX_CHAR_PER_LINE-MAX_CHAR_PER_NUM };
// Initialize table
unsigned char bin2dec[256][MAX_CHAR_PER_NUM+1]; //
bin2dec[MAX_CHAR_PER_NUM] => length for (int i = 0; i < 256;++i) {
char tmp[8];
int len = sprintf(tmp, "%d,", i);
memcpy(bin2dec[i], tmp, MAX_CHAR_PER_NUM);
bin2dec[i][MAX_CHAR_PER_NUM] = (unsigned char)len;
}
// main loop
int err = 0;
int c;
unsigned char outbuf[MAX_CHAR_PER_LINE+MAX_CHAR_PER_NUM]; // provide
space for EOL unsigned char* outptr = outbuf;
while ((c = fgetc(fpin)) >= 0) {
unsigned char* dec = bin2dec[c & 255];
memcpy(outptr, dec, MAX_CHAR_PER_NUM);
outptr += dec[MAX_CHAR_PER_NUM];
if (outptr > &outbuf[ALMOST_FULL_THR]) { // spill output buffer
*outptr++ = '\n';
ptrdiff_t wrlen = fwrite(outbuf, 1, outptr-outbuf, fpout);
if (wrlen != outptr-outbuf) {
err = 2;
break;
}
outptr = outbuf;
}
}
if (ferror(fpin)) {
perror(infilename);
err = 1;
}
// last line
if (outptr != outbuf && err == 0) {
*outptr++ = '\n';
ptrdiff_t wrlen = fwrite(outbuf, 1, outptr-outbuf, fpout);
if (wrlen != outptr-outbuf)
err = 2;
}
// completion and cleanup
if (err == 2 && outfilename)
perror(outfilename);
fclose(fpin);
if (outfilename) {
fclose(fpout);
if (err)
remove(outfilename);
}
return err;
}