From a7944bb2570cc777a10860813fd725d704e28b6d Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Mon, 21 Nov 2005 17:01:50 +0000 Subject: [PATCH] Added pj_stricmp_alnum() to speedup the parser!!! git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@72 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib/include/pj/string.h | 22 ++++- pjlib/include/pj/string_i.h | 50 ++++++++++-- pjlib/src/pjlib-test/string.c | 146 +++++++++++++++++++++++++++++++++- 3 files changed, 209 insertions(+), 9 deletions(-) diff --git a/pjlib/include/pj/string.h b/pjlib/include/pj/string.h index c7310b599..83f6ab73e 100644 --- a/pjlib/include/pj/string.h +++ b/pjlib/include/pj/string.h @@ -334,10 +334,28 @@ PJ_IDECL(int) pj_strncmp2( const pj_str_t *str1, const char *str2, * * @return * - < 0 if str1 is less than str2 - * - 0 if str1 is identical to str2 + * - 0 if str1 is equal to str2 * - > 0 if str1 is greater than str2 */ -PJ_IDECL(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2); +PJ_IDECL(int) pj_stricmp(const pj_str_t *str1, const pj_str_t *str2); + +/** + * Perform lowercase comparison to the strings which consists of only + * alnum characters. More over, it will only return non-zero if both + * strings are not equal, and is not able to detect which string is + * 'less'. + * + * If non-alnum inputs are given, then the function may mistakenly + * treat two strings as equal while they're not. + * + * @param str1 The string to compare. + * @param str2 The string to compare. + * + * @return + * - 0 if str1 is equal to str2 + * - (-1) if not equal. + */ +PJ_IDECL(int) pj_stricmp_alnum(const pj_str_t *str1, const pj_str_t *str2); /** * Perform lowercase comparison to the strings. diff --git a/pjlib/include/pj/string_i.h b/pjlib/include/pj/string_i.h index 3fdcd2c39..f800ba846 100644 --- a/pjlib/include/pj/string_i.h +++ b/pjlib/include/pj/string_i.h @@ -17,6 +17,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include + PJ_IDEF(pj_str_t) pj_str(char *str) { pj_str_t dst; @@ -157,13 +159,49 @@ PJ_IDEF(int) pj_strcmp2( const pj_str_t *str1, const char *str2 ) PJ_IDEF(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2) { - pj_ssize_t diff; - - diff = str1->slen - str2->slen; - if (diff) { - return (int)diff; + register int len = str1->slen; + if (len != str2->slen) { + return (int)(len - str2->slen); + } else if (len == 0) { + return 0; } else { - return pj_native_strnicmp(str1->ptr, str2->ptr, str1->slen); + return pj_native_strnicmp(str1->ptr, str2->ptr, len); + } +} + +PJ_IDEF(int) pj_stricmp_alnum(const pj_str_t *str1, const pj_str_t *str2) +{ + register int len = str1->slen; + + if (len != str2->slen) { + return -1; + } else if (len == 0) { + return 0; + } else { + register const pj_uint32_t *p1 = (pj_uint32_t*)str1->ptr, + *p2 = (pj_uint32_t*)str2->ptr; + while (len > 3 && (*p1 & 0x1F1F1F1F)==(*p2 & 0x1F1F1F1F)) + ++p1, ++p2, len-=4; + + if (len > 3) + return -1; +#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0 + else if (len==3) + return ((*p1 & 0x001F1F1F)==(*p2 & 0x001F1F1F)) ? 0 : -1; + else if (len==2) + return ((*p1 & 0x00001F1F)==(*p2 & 0x00001F1F)) ? 0 : -1; + else if (len==1) + return ((*p1 & 0x0000001F)==(*p2 & 0x0000001F)) ? 0 : -1; +#else + else if (len==3) + return ((*p1 & 0x1F1F1F00)==(*p2 & 0x1F1F1F00)) ? 0 : -1; + else if (len==2) + return ((*p1 & 0x1F1F0000)==(*p2 & 0x1F1F0000)) ? 0 : -1; + else if (len==1) + return ((*p1 & 0x1F000000)==(*p2 & 0x1F000000)) ? 0 : -1; +#endif + else + return 0; } } diff --git a/pjlib/src/pjlib-test/string.c b/pjlib/src/pjlib-test/string.c index 96a4ade14..fd94b03c1 100644 --- a/pjlib/src/pjlib-test/string.c +++ b/pjlib/src/pjlib-test/string.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "test.h" /** @@ -63,6 +64,148 @@ #define JUST_HELLO "Hello" #define UL_VALUE 3456789012UL +static int stricmp_test(void) +{ +#define STRTEST(res,S1,S2,code) \ + do { \ + s1.ptr=S1; s1.slen=len; \ + s2.ptr=S2; s2.slen=len; \ + pj_get_timestamp(&t1); \ + if (pj_stricmp(&s1,&s2)!=res) return code; \ + pj_get_timestamp(&t2); \ + pj_sub_timestamp(&t2, &t1); \ + pj_add_timestamp(&e1, &t2); \ + pj_get_timestamp(&t1); \ + if (pj_stricmp_alnum(&s1,&s2)!=res) return code-1; \ + pj_get_timestamp(&t2); \ + pj_sub_timestamp(&t2, &t1); \ + pj_add_timestamp(&e2, &t2); \ + } while (0) + + char *buf; + pj_str_t s1, s2; + pj_timestamp t1, t2, e1, e2, zero; + pj_uint32_t c1, c2; + int len; + + e1.u32.hi = e1.u32.lo = e2.u32.hi = e2.u32.lo = 0; + + pj_thread_sleep(0); + + /* Compare empty strings. */ + len=0; + STRTEST( 0, "","",-500); + + /* equal, length=1 + * use buffer to simulate non-aligned string. + */ + buf = "a""A"; + len=1; + STRTEST( 0, "a",buf+0,-510); + STRTEST( 0, "a",buf+1,-512); + + /* equal, length=2 + * use buffer to simulate non-aligned string. + */ + buf = "aa""Aa""aA""AA"; + len=2; + STRTEST( 0, "aa",buf+0,-520); + STRTEST( 0, "aa",buf+2,-522); + STRTEST( 0, "aa",buf+4,-524); + STRTEST( 0, "aa",buf+6,-524); + + /* equal, length=3 + * use buffer to simulate non-aligned string. + */ + buf = "aaa""Aaa""aAa""aaA""AAa""aAA""AaA""AAA"; + len=3; + STRTEST( 0, "aaa",buf+0,-530); + STRTEST( 0, "aaa",buf+3,-532); + STRTEST( 0, "aaa",buf+6,-534); + STRTEST( 0, "aaa",buf+9,-536); + STRTEST( 0, "aaa",buf+12,-538); + STRTEST( 0, "aaa",buf+15,-540); + STRTEST( 0, "aaa",buf+18,-542); + STRTEST( 0, "aaa",buf+21,-534); + + /* equal, length=4 */ + len=4; + STRTEST( 0, "aaaa","aaaa",-540); + STRTEST( 0, "aaaa","Aaaa",-542); + STRTEST( 0, "aaaa","aAaa",-544); + STRTEST( 0, "aaaa","aaAa",-546); + STRTEST( 0, "aaaa","aaaA",-548); + STRTEST( 0, "aaaa","AAaa",-550); + STRTEST( 0, "aaaa","aAAa",-552); + STRTEST( 0, "aaaa","aaAA",-554); + STRTEST( 0, "aaaa","AaAa",-556); + STRTEST( 0, "aaaa","aAaA",-558); + STRTEST( 0, "aaaa","AaaA",-560); + STRTEST( 0, "aaaa","AAAa",-562); + STRTEST( 0, "aaaa","aAAA",-564); + STRTEST( 0, "aaaa","AAaA",-566); + STRTEST( 0, "aaaa","AaAA",-568); + STRTEST( 0, "aaaa","AAAA",-570); + + /* equal, length=5 */ + buf = "aaaAa""AaaaA""AaAaA""AAAAA"; + len=5; + STRTEST( 0, "aaaaa",buf+0,-580); + STRTEST( 0, "aaaaa",buf+5,-582); + STRTEST( 0, "aaaaa",buf+10,-584); + STRTEST( 0, "aaaaa",buf+15,-586); + + /* not equal, length=1 */ + len=1; + STRTEST( -1, "a", "b", -600); + + /* not equal, length=2 */ + buf = "ab""ba"; + len=2; + STRTEST( -1, "aa", buf+0, -610); + STRTEST( -1, "aa", buf+2, -612); + + /* not equal, length=3 */ + buf = "aab""aba""baa"; + len=3; + STRTEST( -1, "aaa", buf+0, -620); + STRTEST( -1, "aaa", buf+3, -622); + STRTEST( -1, "aaa", buf+6, -624); + + /* not equal, length=4 */ + buf = "aaab""aaba""abaa""baaa"; + len=4; + STRTEST( -1, "aaaa", buf+0, -630); + STRTEST( -1, "aaaa", buf+4, -632); + STRTEST( -1, "aaaa", buf+8, -634); + STRTEST( -1, "aaaa", buf+12, -636); + + /* not equal, length=5 */ + buf="aaaab""aaaba""aabaa""abaaa""baaaa"; + len=5; + STRTEST( -1, "aaaaa", buf+0, -640); + STRTEST( -1, "aaaaa", buf+5, -642); + STRTEST( -1, "aaaaa", buf+10, -644); + STRTEST( -1, "aaaaa", buf+15, -646); + STRTEST( -1, "aaaaa", buf+20, -648); + + zero.u32.hi = zero.u32.lo = 0; + c1 = pj_elapsed_cycle(&zero, &e1); + c2 = pj_elapsed_cycle(&zero, &e2); + + if (c1 < c2) { + PJ_LOG(3,("", " error: pj_stricmp_alnum is slower than pj_stricmp!")); + return -700; + } + + PJ_LOG(3, ("", " time: stricmp=%u, stricmp_alnum=%u (speedup=%d.%02dx)", + c1, c2, + (c1 * 100 / c2) / 100, + (c1 * 100 / c2) % 100)); + return 0; +#undef STRTEST +} + int string_test(void) { const pj_str_t hello_world = { HELLO_WORLD, strlen(HELLO_WORLD) }; @@ -162,7 +305,8 @@ int string_test(void) /* Done. */ pj_pool_release(pool); - return 0; + + return stricmp_test(); } #else