Here are a couple of performance tuneups for strftime.c.
1. Instead of using arrays of pointers to arrays of chars, use two-dimensional
arrays of chars, since the sizes are all known. This tends to use less
space (since you don't need to store the pointers) and time (since you
don't need to indirect through them.
2. Instead of passing around a pointer and pointer to size,
incrementing the former and decrementing the latter indirectly, just
pass around a pointer and its limit. That way, you can avoid the extra
indirection and decrementation.
These two changes lop 10% off the code size (sparc, GCC 2.4.0 with -O2).
Here's a patch, which assumes my previous patch was applied.
*** draft-strftime1.c Tue May 25 11:28:38 1993
--- draft-strftime2.c Tue May 25 21:07:08 1993
***************
*** 32,56 ****
#include "private.h"
#include "tzfile.h"
! static const char * const afmt[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
! static const char * const Afmt[] = {
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday"
};
! static const char * const bfmt[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"
};
! static const char * const Bfmt[] = {
"January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"
};
! static char *_add P((const char *, size_t *, char *));
! static char *_conv P((int, const char *, size_t *, char *));
! static char *_fmt P((const char *, const struct tm *, size_t *, char *));
size_t strftime P((char *, size_t, const char *, const struct tm *));
--- 32,56 ----
#include "private.h"
#include "tzfile.h"
! static const char afmt[][4] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
! static const char Afmt[][10] = {
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday"
};
! static const char bfmt[][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"
};
! static const char Bfmt[][10] = {
"January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"
};
! static char *_add P((const char *, char *, const char *));
! static char *_conv P((int, const char *, char *, const char *));
! static char *_fmt P((const char *, const struct tm *, char *, const char *));
size_t strftime P((char *, size_t, const char *, const struct tm *));
***************
*** 61,82 ****
const char *format;
const struct tm *t;
{
! size_t gsize;
! gsize = maxsize;
! s = _fmt(format, t, &gsize, s);
! if (gsize <= 0)
return 0;
! *s = '\0';
! return maxsize - gsize;
}
static char *
! _fmt(format, t, gsizep, pt)
const char *format;
const struct tm *t;
- size_t *gsizep;
char *pt;
{
for (; *format; ++format) {
if (*format == '%') {
--- 61,81 ----
const char *format;
const struct tm *t;
{
! char *p;
! p = _fmt(format, t, s, s + maxsize);
! if (p == s + maxsize)
return 0;
! *p = '\0';
! return p - s;
}
static char *
! _fmt(format, t, pt, ptlim)
const char *format;
const struct tm *t;
char *pt;
+ const char *ptlim;
{
for (; *format; ++format) {
if (*format == '%') {
***************
*** 87,109 ****
break;
case 'A':
pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
! "?" : Afmt[t->tm_wday], gsizep, pt);
continue;
case 'a':
pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
! "?" : afmt[t->tm_wday], gsizep, pt);
continue;
case 'B':
pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
! "?" : Bfmt[t->tm_mon], gsizep, pt);
continue;
case 'b':
case 'h':
pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
! "?" : bfmt[t->tm_mon], gsizep, pt);
continue;
case 'c':
! pt = _fmt("%D %X", t, gsizep, pt);
continue;
case 'C':
/*
--- 86,108 ----
break;
case 'A':
pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
! "?" : Afmt[t->tm_wday], pt, ptlim);
continue;
case 'a':
pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
! "?" : afmt[t->tm_wday], pt, ptlim);
continue;
case 'B':
pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
! "?" : Bfmt[t->tm_mon], pt, ptlim);
continue;
case 'b':
case 'h':
pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
! "?" : bfmt[t->tm_mon], pt, ptlim);
continue;
case 'c':
! pt = _fmt("%D %X", t, pt, ptlim);
continue;
case 'C':
/*
***************
*** 114,120 ****
** (ado, 5/24/93)
*/
pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,
! "%02d", gsizep, pt);
continue;
case 'D':
case 'x':
--- 113,119 ----
** (ado, 5/24/93)
*/
pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,
! "%02d", pt, ptlim);
continue;
case 'D':
case 'x':
***************
*** 129,138 ****
** numbers (as here) makes Quakers happier.
** This is the ISO standard date format.
*/
! pt = _fmt("%Y-%m-%d", t, gsizep, pt);
continue;
case 'd':
! pt = _conv(t->tm_mday, "%02d", gsizep, pt);
continue;
case 'E':
case 'O':
--- 128,137 ----
** numbers (as here) makes Quakers happier.
** This is the ISO standard date format.
*/
! pt = _fmt("%Y-%m-%d", t, pt, ptlim);
continue;
case 'd':
! pt = _conv(t->tm_mday, "%02d", pt, ptlim);
continue;
case 'E':
case 'O':
***************
*** 149,166 ****
*/
goto label;
case 'e':
! pt = _conv(t->tm_mday, "%2d", gsizep, pt);
continue;
case 'H':
! pt = _conv(t->tm_hour, "%02d", gsizep, pt);
continue;
case 'I':
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
! "%02d", gsizep, pt);
continue;
case 'j':
! pt = _conv(t->tm_yday + 1, "%03d", gsizep, pt);
continue;
case 'k':
/*
--- 148,165 ----
*/
goto label;
case 'e':
! pt = _conv(t->tm_mday, "%2d", pt, ptlim);
continue;
case 'H':
! pt = _conv(t->tm_hour, "%02d", pt, ptlim);
continue;
case 'I':
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
! "%02d", pt, ptlim);
continue;
case 'j':
! pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
continue;
case 'k':
/*
***************
*** 173,186 ****
** "%l" have been swapped.
** (ado, 5/24/93)
*/
! pt = _conv(t->tm_hour, "%2d", gsizep, pt);
continue;
#ifdef KITCHEN_SINK
case 'K':
/*
** After all this time, still unclaimed!
*/
! pt = _add("kitchen sink", gsizep, pt);
continue;
#endif /* defined KITCHEN_SINK */
case 'l':
--- 172,185 ----
** "%l" have been swapped.
** (ado, 5/24/93)
*/
! pt = _conv(t->tm_hour, "%2d", pt, ptlim);
continue;
#ifdef KITCHEN_SINK
case 'K':
/*
** After all this time, still unclaimed!
*/
! pt = _add("kitchen sink", pt, ptlim);
continue;
#endif /* defined KITCHEN_SINK */
case 'l':
***************
*** 195,234 ****
*/
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
! "%2d", gsizep, pt);
continue;
case 'M':
! pt = _conv(t->tm_min, "%02d", gsizep, pt);
continue;
case 'm':
! pt = _conv(t->tm_mon + 1, "%02d", gsizep, pt);
continue;
case 'n':
! pt = _add("\n", gsizep, pt);
continue;
case 'p':
pt = _add(t->tm_hour >= 12 ? "PM" : "AM",
! gsizep, pt);
continue;
case 'R':
! pt = _fmt("%H:%M", t, gsizep, pt);
continue;
case 'r':
! pt = _fmt("%I:%M:%S %p", t, gsizep, pt);
continue;
case 'S':
! pt = _conv(t->tm_sec, "%02d", gsizep, pt);
continue;
case 'T':
case 'X':
! pt = _fmt("%H:%M:%S", t, gsizep, pt);
continue;
case 't':
! pt = _add("\t", gsizep, pt);
continue;
case 'U':
pt = _conv((t->tm_yday + 7 - t->tm_wday) / 7,
! "%02d", gsizep, pt);
continue;
case 'u':
/*
--- 194,233 ----
*/
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
! "%2d", pt, ptlim);
continue;
case 'M':
! pt = _conv(t->tm_min, "%02d", pt, ptlim);
continue;
case 'm':
! pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
continue;
case 'n':
! pt = _add("\n", pt, ptlim);
continue;
case 'p':
pt = _add(t->tm_hour >= 12 ? "PM" : "AM",
! pt, ptlim);
continue;
case 'R':
! pt = _fmt("%H:%M", t, pt, ptlim);
continue;
case 'r':
! pt = _fmt("%I:%M:%S %p", t, pt, ptlim);
continue;
case 'S':
! pt = _conv(t->tm_sec, "%02d", pt, ptlim);
continue;
case 'T':
case 'X':
! pt = _fmt("%H:%M:%S", t, pt, ptlim);
continue;
case 't':
! pt = _add("\t", pt, ptlim);
continue;
case 'U':
pt = _conv((t->tm_yday + 7 - t->tm_wday) / 7,
! "%02d", pt, ptlim);
continue;
case 'u':
/*
***************
*** 238,244 ****
** (ado, 5/24/93)
*/
pt = _conv((t->tm_wday == 0) ? 7 : t->tm_wday,
! "%d", gsizep, pt);
continue;
case 'V':
/*
--- 237,243 ----
** (ado, 5/24/93)
*/
pt = _conv((t->tm_wday == 0) ? 7 : t->tm_wday,
! "%d", pt, ptlim);
continue;
case 'V':
/*
***************
*** 270,276 ****
i = (t->tm_yday + 10 - (t->tm_wday ?
(t->tm_wday - 1) : 6)) / 7;
pt = _conv((i == 0) ? 53 : i,
! "%02d", gsizep, pt);
}
continue;
case 'v':
--- 269,275 ----
i = (t->tm_yday + 10 - (t->tm_wday ?
(t->tm_wday - 1) : 6)) / 7;
pt = _conv((i == 0) ? 53 : i,
! "%02d", pt, ptlim);
}
continue;
case 'v':
***************
*** 279,315 ****
** "date as dd-bbb-YYYY"
** (ado, 5/24/93)
*/
! pt = _fmt("%e-%b-%Y", t, gsizep, pt);
continue;
case 'W':
pt = _conv((t->tm_yday + 7 -
(t->tm_wday ?
(t->tm_wday - 1) : 6)) / 7,
! "%02d", gsizep, pt);
continue;
case 'w':
! pt = _conv(t->tm_wday, "%d", gsizep, pt);
continue;
case 'y':
pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
! "%02d", gsizep, pt);
continue;
case 'Y':
pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",
! gsizep, pt);
continue;
case 'Z':
#ifdef TM_ZONE
if (t->TM_ZONE)
! pt = _add(t->TM_ZONE, gsizep, pt);
else
#endif /* defined TM_ZONE */
if (t->tm_isdst == 0 || t->tm_isdst == 1) {
extern char * tzname[2];
pt = _add(tzname[t->tm_isdst],
! gsizep, pt);
! } else pt = _add("?", gsizep, pt);
continue;
case '%':
/*
--- 278,314 ----
** "date as dd-bbb-YYYY"
** (ado, 5/24/93)
*/
! pt = _fmt("%e-%b-%Y", t, pt, ptlim);
continue;
case 'W':
pt = _conv((t->tm_yday + 7 -
(t->tm_wday ?
(t->tm_wday - 1) : 6)) / 7,
! "%02d", pt, ptlim);
continue;
case 'w':
! pt = _conv(t->tm_wday, "%d", pt, ptlim);
continue;
case 'y':
pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
! "%02d", pt, ptlim);
continue;
case 'Y':
pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",
! pt, ptlim);
continue;
case 'Z':
#ifdef TM_ZONE
if (t->TM_ZONE)
! pt = _add(t->TM_ZONE, pt, ptlim);
else
#endif /* defined TM_ZONE */
if (t->tm_isdst == 0 || t->tm_isdst == 1) {
extern char * tzname[2];
pt = _add(tzname[t->tm_isdst],
! pt, ptlim);
! } else pt = _add("?", pt, ptlim);
continue;
case '%':
/*
***************
*** 321,356 ****
break;
}
}
! if (*gsizep <= 0)
return pt;
*pt++ = *format;
- --*gsizep;
}
return pt;
}
static char *
! _conv(n, format, gsizep, pt)
int n;
const char *format;
- size_t *gsizep;
char *pt;
{
char buf[21]; /* Room for - 2**63 ("-9223372036854775808") + null. */
(void) sprintf(buf, format, n);
! return _add(buf, gsizep, pt);
}
static char *
! _add(str, gsizep, pt)
const char *str;
- size_t *gsizep;
char *pt;
{
! while (*gsizep > 0 && (*pt = *str++) != '\0') {
++pt;
- --*gsizep;
}
return pt;
}
--- 320,353 ----
break;
}
}
! if (pt == ptlim)
return pt;
*pt++ = *format;
}
return pt;
}
static char *
! _conv(n, format, pt, ptlim)
int n;
const char *format;
char *pt;
+ const char *ptlim;
{
char buf[21]; /* Room for - 2**63 ("-9223372036854775808") + null. */
(void) sprintf(buf, format, n);
! return _add(buf, pt, ptlim);
}
static char *
! _add(str, pt, ptlim)
const char *str;
char *pt;
+ const char *ptlim;
{
! while (pt < ptlim && (*pt = *str++) != '\0') {
++pt;
}
return pt;
}