Was looking at the strlcat() implementation in the PHP source
and saw that it does not take advantage of history :).
Look at xxx_strlcat() in the following example.
You are almost always better off using the compiler's built-in
string functions, due to the optimizations built-in (many years ago)
to improve Dhrystone benchmark scores. The benchmark turned out to
be a bit bogus, but the improvements made to the string functions
are a benefit to us all :).
This is more readable (and thus more likely correct), slightly faster
(about 4% in my testing), and in the debug build better checked.
Full comparison benchmark program:
-----
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <assert.h>
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t php_strlcat(char* dst,const char* src,size_t siz)
{
register char *d = dst;
register const char *s = src;
register size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (*d != '\0' && n-- != 0)
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}
/*
* Take full advantage of any compiler/library optimizations built in
* to the standard string routines. Look up the history of compiler
* comparisons with Dhrystone benchmark to understand why this wins.
* Pre-Internet history - check Google's USENET archive.
*/
size_t xxx_strlcat(char* s1,const char* s2,size_t nMax)
{
size_t n1 = strlen(s1);
size_t n2 = strlen(s2);
size_t nCopy = (nMax <= (n1+n2)) ? (nMax - n1 - 1) : n2;
/* Better to leave this out and require a valid string return */
if (!nMax) return 0;
assert(n1 < nMax); /* Catch pre-existing oversize strings */
assert(0 < nMax); /* Insure return is always a valid string */
memcpy(s1+n1,s2,nCopy);
s1[n1+nCopy] = 0;
return n1+n2; /* as documented for strlcat() */
/*return n1+nCopy; /* actual number of characters */
}
/*
*
*/
int main(int ac, char** av)
{
clock_t t1,dt;
#ifdef WIN32
__int64 nTotal;
#else
long long nTotal;
#endif
char s1[85];
static char s2[] = "1234567890";
int nLoops = 10;
if (1 < ac) {
nLoops = atoi(av[1]);
}
printf("Compare two strlcat() implementations for %d iterations.\n",nLoops);
t1 = clock();
nTotal = 0;
for (int i=0; i<nLoops; ++i) {
s1[0] = 0;
nTotal += php_strlcat(s1,s2,sizeof(s1));
nTotal += php_strlcat(s1,s2,sizeof(s1));
nTotal += php_strlcat(s1,s2,sizeof(s1));
nTotal += php_strlcat(s1,s2,sizeof(s1));
nTotal += php_strlcat(s1,s2,sizeof(s1));
nTotal += php_strlcat(s1,s2,sizeof(s1));
nTotal += php_strlcat(s1,s2,sizeof(s1));
nTotal += php_strlcat(s1,s2,sizeof(s1));
nTotal += php_strlcat(s1,s2,sizeof(s1));
nTotal += php_strlcat(s1,s2,sizeof(s1));
}
dt = clock() - t1;
printf("php_strlcat() copied %1.0f characters in %ld
ticks\n",(double)nTotal,(long)dt);
t1 = clock();
nTotal = 0;
for (i=0; i<nLoops; ++i) {
s1[0] = 0;
nTotal += xxx_strlcat(s1,s2,sizeof(s1));
nTotal += xxx_strlcat(s1,s2,sizeof(s1));
nTotal += xxx_strlcat(s1,s2,sizeof(s1));
nTotal += xxx_strlcat(s1,s2,sizeof(s1));
nTotal += xxx_strlcat(s1,s2,sizeof(s1));
nTotal += xxx_strlcat(s1,s2,sizeof(s1));
nTotal += xxx_strlcat(s1,s2,sizeof(s1));
nTotal += xxx_strlcat(s1,s2,sizeof(s1));
nTotal += xxx_strlcat(s1,s2,sizeof(s1));
nTotal += xxx_strlcat(s1,s2,sizeof(s1));
}
dt = clock() - t1;
printf("xxx_strlcat() copied %1.0f characters in %ld
ticks\n",(double)nTotal,(long)dt);
return 0;
}
-----
--
Preston L. Bannister
http://members.cox.net/preston.bannister/
pbannister on Yahoo Messenger
--
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php