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