Re: A better strlcat()

From: Date: Thu, 02 May 2002 17:15:17 +0000
Subject: Re: A better strlcat()
References: 1  Groups: php.dev 
Request: Send a blank email to php-dev+get-83616@lists.php.net to get a copy of this message
Are you sure it behaves *exactly* like the existing one? I stole the implementation from OpenBSD so it might be a good idea for you to send it to them. They are the best to shed light on this and see if it's exactly the same and faster. Andi At 09:00 02/05/2002 -0700, Preston L. Bannister wrote:
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


« previous php.dev (#83616) next »