Hi List, attached is a patch that adds more 'const' modifiers to 'Octstr' and get better 'octstr' performance (some functions were hand-optimized but not all, means more work should be done;)). Also you can find some simple benchmarks in attached .txt file.
Comments and votes please! -- Best regards / Mit besten Grüßen aus Düsseldorf Dipl.-Ing. Alexander Malysh ___________________________________________ Centrium GmbH Vogelsanger Weg 80 40470 Düsseldorf Fon: +49 (0211) 74 84 51 80 Fax: +49 (0211) 277 49 109 email: [EMAIL PROTECTED] web: www.centrium.de msn: [EMAIL PROTECTED] icq: 98063111 ___________________________________________ Please avoid sending me Word, Excel or PowerPoint attachments. See http://www.fsf.org/philosophy/no-word-attachments.html
Index: gwlib/octstr.c =================================================================== RCS file: /home/cvs/gateway/gwlib/octstr.c,v retrieving revision 1.154 diff -a -u -r1.154 octstr.c --- gwlib/octstr.c 2 Dec 2003 09:21:26 -0000 1.154 +++ gwlib/octstr.c 19 Jan 2004 11:53:43 -0000 @@ -142,6 +142,13 @@ */ #define CSTR_TO_LONG(ptr) (((long) ptr) >> 2) + +/* + * HEX to ASCII + */ +#define H2B(a) (a >= '0' && a <= '9' ? a - '0' : (a >= 'a' && a <= 'f' ? a - 'a' + 10 : (a >= 'A' && a <= 'F' ? a - 'A' + 10 : -1))) + + /*********************************************************************** * Declarations of internal functions. These are defined at the end of * the file. @@ -174,6 +181,8 @@ size++; /* make room for the invisible terminating NUL */ if (size > ostr->size) { + /* allways reallocate in 1kB chunks */ + size += 1024 - (size % 1024); ostr->data = gw_realloc(ostr->data, size); ostr->size = size; } @@ -325,7 +334,7 @@ } -Octstr *octstr_copy_real(Octstr *ostr, long from, long len, const char *file, long line, +Octstr *octstr_copy_real(const Octstr *ostr, long from, long len, const char *file, long line, const char *func) { seems_valid(ostr); @@ -378,7 +387,7 @@ } -int octstr_get_char(Octstr *ostr, long pos) +int octstr_get_char(const Octstr *ostr, long pos) { seems_valid(ostr); if (pos >= ostr->len || pos < 0) @@ -440,7 +449,7 @@ void octstr_binary_to_hex(Octstr *ostr, int uppercase) { unsigned char *hexits; - long i; + long i, tmp; seems_valid(ostr); gw_assert(!ostr->immutable); @@ -454,8 +463,9 @@ * overwriting the data while we read it. Even the order of * the two assignments is important, to get i == 0 right. */ for (i = ostr->len - 1; i >= 0; i--) { - ostr->data[i * 2 + 1] = hexits[ostr->data[i] % 16]; - ostr->data[i * 2] = hexits[(ostr->data[i] / 16) & 0xf]; + tmp = i << 1; /* tmp = i * 2; */ + ostr->data[tmp + 1] = hexits[ostr->data[i] & 0xf]; + ostr->data[tmp] = hexits[ostr->data[i] >> 4]; } ostr->len = ostr->len * 2; @@ -909,7 +919,20 @@ } -int octstr_search_char(Octstr *ostr, int ch, long pos) +int octstr_str_ncompare(const Octstr *ostr, const char *str, long n) +{ + seems_valid(ostr); + + if (str == NULL) + return -1; + if (ostr->data == NULL) + return 1; /* str grater */ + + return strncmp(ostr->data, str, n); +} + + +int octstr_search_char(const Octstr *ostr, int ch, long pos) { unsigned char *p; @@ -928,7 +951,7 @@ } -int octstr_search_chars(Octstr *ostr, Octstr *chars, long pos) +int octstr_search_chars(const Octstr *ostr, const Octstr *chars, long pos) { long i, j; for(i=0; i < octstr_len(chars); i++) { @@ -940,7 +963,7 @@ } -int octstr_search(Octstr *haystack, Octstr *needle, long pos) +int octstr_search(const Octstr *haystack, const Octstr *needle, long pos) { int first; @@ -972,7 +995,7 @@ } -int octstr_case_search(Octstr *haystack, Octstr *needle, long pos) +int octstr_case_search(const Octstr *haystack, const Octstr *needle, long pos) { long i, j; int c1, c2; @@ -999,7 +1022,7 @@ return -1; } -int octstr_case_nsearch(Octstr *haystack, Octstr *needle, long pos, long n) +int octstr_case_nsearch(const Octstr *haystack, const Octstr *needle, long pos, long n) { long i, j; int c1, c2; @@ -1139,7 +1162,7 @@ } -void octstr_insert(Octstr *ostr1, Octstr *ostr2, long pos) +void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos) { seems_valid(ostr1); seems_valid(ostr2); @@ -1334,7 +1357,7 @@ } -void octstr_append(Octstr *ostr1, Octstr *ostr2) +void octstr_append(Octstr *ostr1, const Octstr *ostr2) { gw_assert(ostr1 != NULL); octstr_insert(ostr1, ostr2, ostr1->len); @@ -1432,7 +1455,7 @@ } -List *octstr_split_words(Octstr *ostr) +List *octstr_split_words(const Octstr *ostr) { unsigned char *p; List *list; @@ -1470,7 +1493,7 @@ } -List *octstr_split(Octstr *os, Octstr *sep) +List *octstr_split(const Octstr *os, const Octstr *sep) { List *list; long next, pos, seplen; @@ -1502,8 +1525,7 @@ return octstr_case_compare(item, pattern) == 0; } - -void octstr_dump(Octstr *ostr, int level) +void octstr_dump(const Octstr *ostr, int level) { unsigned char *p, *d, buf[1024], charbuf[256]; long pos; @@ -1604,61 +1626,56 @@ octstr_dump(ostr, level + 1); } + void octstr_url_encode(Octstr *ostr) { - int i, n, newlen; - unsigned char *str, *str2, *hexits; - unsigned char c; - Octstr *res; + long i, n, len; + unsigned char c, *str, *str2, *res, *hexits; seems_valid(ostr); if (ostr->immutable || ostr->len == 0) - return; + return; - res = octstr_create(""); - str = ostr->data; - n = 0; - for (i = 0; i < ostr->len; i++) + /* calculate new length */ + for (i = 0, str = ostr->data, n = 0; i < ostr->len; i++) if (!is_safe[*str++]) n++; - newlen = ostr->len + 2 * n; - res->len = newlen; - res->size = res->len + 1; - res->data = gw_malloc(res->size); + + if (n == 0) /* we are done, all chars are safe */ + return; hexits = "0123456789ABCDEF"; - str = ostr->data; - str2 = res->data; - for (i = 0; i < ostr->len; i++) { - c = *str++; - if (!is_safe[c]) { - *str2++ = '%'; - *str2++ = hexits[c >> 4 & 0xf]; - *str2++ = hexits[c & 0xf]; - } - else if (c == ' ') - *str2++ = '+'; - else - *str2++ = c; + res = str2 = gw_malloc((len = ostr->len + 2 * n + 1)); + + for (i = 0, str = ostr->data; i < ostr->len; i++) { + c = *str++; + if (!is_safe[c]) { + *str2++ = '%'; + *str2++ = hexits[c >> 4 & 0xf]; + *str2++ = hexits[c & 0xf]; + } + else if (c == ' ') + *str2++ = '+'; + else + *str2++ = c; } *str2 = 0; - seems_valid(res); - - octstr_truncate(ostr, 0); - octstr_insert(ostr, res, 0); - octstr_destroy(res); + gw_free(ostr->data); + ostr->data = res; + ostr->size = len; + ostr->len = len - 1; + + seems_valid(ostr); } int octstr_url_decode(Octstr *ostr) { - long value; unsigned char *string = ostr->data; unsigned char *dptr = ostr->data; - unsigned char buf[3]; /* buffer for strtol conversion */ - buf[2] = '\0'; + int code, code2, ret = 0; seems_valid(ostr); gw_assert(!ostr->immutable); @@ -1668,39 +1685,40 @@ do { if (*string == '%') { - if (*(string + 1) == '\0' || *(string + 2) == '\0') - goto error; - buf[0] = *(string + 1); - buf[1] = *(string + 2); - value = strtol(buf, NULL, 16); - - if (value >= 0 && value < 256) { - *dptr = (unsigned char)value; - string += 3; - dptr++; + if (*(string + 1) == '\0' || *(string + 2) == '\0') { + warning(0, "octstr_url_decode: corrupted end-of-string <%s>", string); + ret = -1; + break; + } + + code = H2B(*(string + 1)); + code2 = H2B(*(string + 2)); + + if (code == -1 || code2 == -1) { + warning(0, "octstr_url_decode: garbage detected (%c%c%c) skipping.", + *string, *(string + 1), *(string + 2)); + *dptr++ = *string++; + *dptr++ = *string++; + *dptr++ = *string++; + ret = -1; continue; } - warning(0, "Garbage encoded (value = %ld)", value); + + *dptr++ = code << 4 | code2; + string += 3; } - if (*string == '+') { + else if (*string == '+') { *dptr++ = ' '; string++; } else *dptr++ = *string++; } while (*string); /* we stop here because it terimates encoded string */ - *dptr = '\0'; - - ostr->len = (dptr - ostr->data); - - seems_valid(ostr); - return 0; -error: *dptr = '\0'; ostr->len = (dptr - ostr->data); - warning(0, "octstr_url_decode: corrupted end-of-string <%s>", string); + seems_valid(ostr); - return -1; + return ret; } Index: gwlib/octstr.h =================================================================== RCS file: /home/cvs/gateway/gwlib/octstr.h,v retrieving revision 1.81 diff -a -u -r1.81 octstr.h --- gwlib/octstr.h 2 Dec 2003 09:21:44 -0000 1.81 +++ gwlib/octstr.h 19 Jan 2004 11:53:43 -0000 @@ -173,7 +173,7 @@ * octet string is created. If `from+len' is after the end of `ostr', * `len' is reduced appropriately. */ -Octstr *octstr_copy_real(Octstr *ostr, long from, long len, const char *file, +Octstr *octstr_copy_real(const Octstr *ostr, long from, long len, const char *file, long line, const char *func); #define octstr_copy(ostr, from, len) \ gw_claim_area(octstr_copy_real((ostr), (from), (len), __FILE__, __LINE__, __func__)) @@ -200,7 +200,7 @@ * value has a range of 0..255 for valid positions, and -1 if `pos' is * after the end of the octet string. */ -int octstr_get_char(Octstr *ostr, long pos); +int octstr_get_char(const Octstr *ostr, long pos); /* @@ -332,6 +332,12 @@ /* + * Same as octstr_str_compare, but comparing is done only up to n bytes. + */ +int octstr_str_ncompare(const Octstr *ostr, const char *str, long n); + + +/* * Write contents of octet string to a file. Return -1 for error, 0 for OK. */ int octstr_print(FILE *f, Octstr *ostr); @@ -341,14 +347,14 @@ * Search the character from octet string starting from position pos. Returns * the position (index) of the char in string, -1 if not found. */ -int octstr_search_char(Octstr *ostr, int ch, long pos); +int octstr_search_char(const Octstr *ostr, int ch, long pos); /* * Search several character from octet string starting from position pos. Returns * the position (index) of the first char found in string, -1 if none was found. */ -int octstr_search_chars(Octstr *ostr, Octstr *chars, long pos); +int octstr_search_chars(const Octstr *ostr, const Octstr *chars, long pos); /* @@ -356,18 +362,18 @@ * Return the start position (index) of 'needle' in 'haystack'. * Return -1 if not found. */ -int octstr_search(Octstr *haystack, Octstr *needle, long pos); +int octstr_search(const Octstr *haystack, const Octstr *needle, long pos); /* * Like octstr_search, but ignores 8-bit byte case. */ -int octstr_case_search(Octstr *haystack, Octstr *needle, long pos); +int octstr_case_search(const Octstr *haystack, const Octstr *needle, long pos); /* * Like octstr_case_search, but searchs only first n octets. */ -int octstr_case_nsearch(Octstr *haystack, Octstr *needle, long pos, long n); +int octstr_case_nsearch(const Octstr *haystack, const Octstr *needle, long pos, long n); /* * Write contents of octet string to a file, in human readable form. @@ -402,7 +408,7 @@ * Insert one octet string into another. `pos' gives the position * in `ostr1' where `ostr2' should be inserted. */ -void octstr_insert(Octstr *ostr1, Octstr *ostr2, long pos); +void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos); /* @@ -429,7 +435,7 @@ /* * Append a second octstr to the first. */ -void octstr_append(Octstr *ostr1, Octstr *ostr2); +void octstr_append(Octstr *ostr1, const Octstr *ostr2); /* @@ -497,14 +503,14 @@ * Split an octet string into words at whitespace, and return a list * containing the new octet strings. */ -List *octstr_split_words(Octstr *ostr); +List *octstr_split_words(const Octstr *ostr); /* * Split an octet string into substrings at every occurence of `sep'. * Return List with the substrings. */ -List *octstr_split(Octstr *os, Octstr *sep); +List *octstr_split(const Octstr *os, const Octstr *sep); /* @@ -522,7 +528,7 @@ /* * Print debugging information about octet string. */ -void octstr_dump(Octstr *ostr, int level); +void octstr_dump(const Octstr *ostr, int level); /*
1) 'octstr_grow' 1kB preallocation chunks: test code: os = octstr_create("qwertzuiopüöä+#lkjhgfdsayxcvbnm,:-<'*`?=)(/&%$§\"!"); for (i=0; i< 10000000; i++) { octstr_append_cstr(os, "as12shdfjshg"); } octstr_destroy(os); w/ prealloc real 0m3.117s user 0m2.455s sys 0m0.640s real 0m3.133s user 0m2.400s sys 0m0.705s real 0m3.123s user 0m2.555s sys 0m0.535s real 0m3.119s user 0m2.520s sys 0m0.560s real 0m3.124s user 0m2.575s sys 0m0.515s w/o prealloc real 0m13.269s user 0m6.490s sys 0m4.155s real 0m10.918s user 0m6.380s sys 0m4.235s real 0m10.734s user 0m6.510s sys 0m4.135s real 0m10.700s user 0m6.485s sys 0m4.120s real 0m10.709s user 0m6.455s sys 0m4.175s 2) optimized 'octstr_binary_to_hex', not too much but... test code: os = octstr_create("qwertzuiopüöä+#lkjhgfdsayxcvbnm,:-<'*`?=)(/&%$§\"!"); for (i=0; i< 1000000; i++) { octstr_binary_to_hex(os, 0); octstr_hex_to_binary(os); } octstr_destroy(os); w/ optimization real 0m7.053s user 0m6.970s sys 0m0.010s real 0m7.251s user 0m6.950s sys 0m0.050s real 0m7.120s user 0m6.960s sys 0m0.010s real 0m7.081s user 0m6.975s sys 0m0.020s real 0m7.058s user 0m6.980s sys 0m0.010s w/o optimization real 0m7.695s user 0m7.600s sys 0m0.025s real 0m7.697s user 0m7.610s sys 0m0.000s real 0m7.689s user 0m7.585s sys 0m0.040s real 0m7.682s user 0m7.595s sys 0m0.015s real 0m7.685s user 0m7.580s sys 0m0.030s 3) octstr_url_encode for (i=0; i < 1000000 ; i++) { os = octstr_create("akljhkajhksfjhakfsjöä#+ü'ß12090ß)(/&%$§"); octstr_url_encode(os); octstr_destroy(os); } w/o optimization real 0m2.862s user 0m2.846s sys 0m0.004s real 0m2.871s user 0m2.853s sys 0m0.002s real 0m2.871s user 0m2.853s sys 0m0.002s real 0m2.881s user 0m2.862s sys 0m0.001s real 0m2.902s user 0m2.871s sys 0m0.002s w/ optimization real 0m1.884s user 0m1.868s sys 0m0.003s real 0m1.891s user 0m1.879s sys 0m0.002s real 0m1.900s user 0m1.875s sys 0m0.003s real 0m1.884s user 0m1.867s sys 0m0.003s real 0m1.881s user 0m1.867s sys 0m0.002s 4) octstr_url_decode test code: os = octstr_create("akljhkajhksfjhakfsjöä#+ü'ß12090ß)(/&%$§"); for (i=0; i < 1000000 ; i++) { octstr_url_encode(os); octstr_url_decode(os); } w/o optimization real 0m2.241s user 0m2.226s sys 0m0.001s real 0m2.247s user 0m2.228s sys 0m0.003s real 0m2.240s user 0m2.223s sys 0m0.004s real 0m2.247s user 0m2.234s sys 0m0.002s real 0m2.244s user 0m2.230s sys 0m0.002s w/ optimization real 0m1.147s user 0m1.133s sys 0m0.003s real 0m1.131s user 0m1.121s sys 0m0.003s real 0m1.128s user 0m1.116s sys 0m0.004s real 0m1.136s user 0m1.123s sys 0m0.002s real 0m1.138s user 0m1.129s sys 0m0.001s 5) octstr_format test code: os1 = octstr_create("qwertzuiopüöä+#lkjhgfdsayxcvbnm,:-<'*`?=)(/&%$§\"!"); for (i=0; i< 1000000; i++) { os = octstr_format("%s %s %d %E", "lsdfjshgdfjshgfsjhg", "kdfl238974jhwdfjhajshg", i, os1); octstr_destroy(os); } w/o opt. real 0m25.285s user 0m24.740s sys 0m0.040s real 0m25.097s user 0m24.710s sys 0m0.085s real 0m25.088s user 0m24.735s sys 0m0.055s real 0m25.520s user 0m24.800s sys 0m0.030s real 0m25.092s user 0m24.720s sys 0m0.060s w/ opt. real 0m20.296s user 0m20.000s sys 0m0.040s real 0m20.290s user 0m19.995s sys 0m0.020s real 0m20.487s user 0m20.025s sys 0m0.040s real 0m20.288s user 0m19.985s sys 0m0.055s real 0m20.284s user 0m20.000s sys 0m0.035s