[Users] [PATCH 3/3] Avoid strlen() on inner loop in textview_make_clickable_parts*()
Igor Mammedov
imammedo at redhat.com
Wed Oct 24 23:41:10 CEST 2012
If "walk" is iterated at very small increments on a big buffer, cost of calling
strcasestr()->strlen(bigbuf) increases drasticaly. Instead compute buffer length
once and then just deal with increments book-keeping.
it reduces cost of strcasestr() in textview_make_clickable_parts*() from 30% to 15%
Signed-off-by: Igor Mammedov <imammedo at redhat.com>
---
src/common/utils.c | 10 ++++++--
src/common/utils.h | 3 +++
src/textview.c | 70 ++++++++++++++++++++++++++++++++----------------------
3 files changed, 53 insertions(+), 30 deletions(-)
diff --git a/src/common/utils.c b/src/common/utils.c
index 46d3ebe..90b71dd 100644
--- a/src/common/utils.c
+++ b/src/common/utils.c
@@ -521,9 +521,15 @@ freeout:
/* Similar to `strstr' but this function ignores the case of both strings. */
gchar *strcasestr(const gchar *haystack, const gchar *needle)
{
- register size_t haystack_len, needle_len;
+ size_t haystack_len = strlen(haystack);
+
+ return strncasestr(haystack, haystack_len, needle);
+}
+
+gchar *strncasestr(const gchar *haystack, gint haystack_len, const gchar *needle)
+{
+ register size_t needle_len;
- haystack_len = strlen(haystack);
needle_len = strlen(needle);
if (haystack_len < needle_len || needle_len == 0)
diff --git a/src/common/utils.h b/src/common/utils.h
index d782199..50f5027 100644
--- a/src/common/utils.h
+++ b/src/common/utils.h
@@ -308,6 +308,9 @@ gchar *strcrchomp (gchar *str);
gint file_strip_crs (const gchar *file);
gchar *strcasestr (const gchar *haystack,
const gchar *needle);
+gchar *strncasestr (const gchar *haystack,
+ gint haystack_len,
+ const gchar *needle);
gpointer my_memmem (gconstpointer haystack,
size_t haystacklen,
gconstpointer needle,
diff --git a/src/textview.c b/src/textview.c
index c1f06e0..8dd8863 100644
--- a/src/textview.c
+++ b/src/textview.c
@@ -1311,7 +1311,8 @@ static void textview_make_clickable_parts(TextView *textview,
GtkTextView *text = GTK_TEXT_VIEW(textview->text);
GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
GtkTextIter iter;
- gchar *mybuf = g_strdup(linebuf);
+ gint mybuf_len = strlen(linebuf);
+ gchar *mybuf = g_strndup(linebuf, mybuf_len);
/* parse table - in order of priority */
struct table {
@@ -1319,6 +1320,7 @@ static void textview_make_clickable_parts(TextView *textview,
/* token search function */
gchar *(*search) (const gchar *haystack,
+ gint haystack_len,
const gchar *needle);
/* part parsing function */
gboolean (*parse) (const gchar *start,
@@ -1332,14 +1334,14 @@ static void textview_make_clickable_parts(TextView *textview,
};
static struct table parser[] = {
- {"http://", strcasestr, get_uri_part, make_uri_string},
- {"https://", strcasestr, get_uri_part, make_uri_string},
- {"ftp://", strcasestr, get_uri_part, make_uri_string},
- {"sftp://", strcasestr, get_uri_part, make_uri_string},
- {"gopher://",strcasestr, get_uri_part, make_uri_string},
- {"www.", strcasestr, get_uri_part, make_http_string},
- {"mailto:", strcasestr, get_uri_part, make_uri_string},
- {"@", strcasestr, get_email_part, make_email_string}
+ {"http://", strncasestr, get_uri_part, make_uri_string},
+ {"https://", strncasestr, get_uri_part, make_uri_string},
+ {"ftp://", strncasestr, get_uri_part, make_uri_string},
+ {"sftp://", strncasestr, get_uri_part, make_uri_string},
+ {"gopher://",strncasestr, get_uri_part, make_uri_string},
+ {"www.", strncasestr, get_uri_part, make_http_string},
+ {"mailto:", strncasestr, get_uri_part, make_uri_string},
+ {"@", strncasestr, get_email_part, make_email_string}
};
const gint PARSE_ELEMS = sizeof parser / sizeof parser[0];
@@ -1354,25 +1356,30 @@ static void textview_make_clickable_parts(TextView *textview,
if (!g_utf8_validate(linebuf, -1, NULL)) {
g_free(mybuf);
- mybuf = g_malloc(strlen(linebuf)*2 +1);
- conv_localetodisp(mybuf, strlen(linebuf)*2 +1, linebuf);
+ mybuf = g_malloc(mybuf_len*2 +1);
+ conv_localetodisp(mybuf, mybuf_len*2 +1, linebuf);
+ mybuf_len = strlen(mybuf);
}
gtk_text_buffer_get_end_iter(buffer, &iter);
/* parse for clickable parts, and build a list of begin and end positions */
for (n = 0; n < PARSE_ELEMS; n++) {
+ gint len = mybuf_len;
+ gint needle_len = strlen(parser[n].needle);
for (walk = mybuf;;) {
- gchar *scanpos = parser[n].search(walk, parser[n].needle);
+ gchar *scanpos = parser[n].search(walk, len, parser[n].needle);
if (scanpos) {
/* check if URI can be parsed */
if (parser[n].parse(walk, scanpos, &bp, &ep, hdr)
- && (size_t) (ep - bp - 1) > strlen(parser[n].needle)) {
+ && (size_t) (ep - bp - 1) > needle_len) {
ADD_TXT_POS(bp, ep, n);
+ len -= ep - walk;
walk = ep;
- } else
- walk = scanpos +
- strlen(parser[n].needle);
+ } else {
+ len -= (scanpos + needle_len) - walk;
+ walk = scanpos + needle_len;
+ }
} else
break;
}
@@ -1423,6 +1430,7 @@ static void textview_make_clickable_parts_later(TextView *textview,
GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
GtkTextIter start_iter, end_iter;
gchar *mybuf;
+ gint mybuf_len;
gint offset = 0;
/* parse table - in order of priority */
struct table {
@@ -1430,6 +1438,7 @@ static void textview_make_clickable_parts_later(TextView *textview,
/* token search function */
gchar *(*search) (const gchar *haystack,
+ gint haystack_len,
const gchar *needle);
/* part parsing function */
gboolean (*parse) (const gchar *start,
@@ -1443,13 +1452,13 @@ static void textview_make_clickable_parts_later(TextView *textview,
};
static struct table parser[] = {
- {"http://", strcasestr, get_uri_part, make_uri_string},
- {"https://", strcasestr, get_uri_part, make_uri_string},
- {"ftp://", strcasestr, get_uri_part, make_uri_string},
- {"sftp://", strcasestr, get_uri_part, make_uri_string},
- {"www.", strcasestr, get_uri_part, make_http_string},
- {"mailto:", strcasestr, get_uri_part, make_uri_string},
- {"@", strcasestr, get_email_part, make_email_string}
+ {"http://", strncasestr, get_uri_part, make_uri_string},
+ {"https://", strncasestr, get_uri_part, make_uri_string},
+ {"ftp://", strncasestr, get_uri_part, make_uri_string},
+ {"sftp://", strncasestr, get_uri_part, make_uri_string},
+ {"www.", strncasestr, get_uri_part, make_http_string},
+ {"mailto:", strncasestr, get_uri_part, make_uri_string},
+ {"@", strncasestr, get_email_part, make_email_string}
};
const gint PARSE_ELEMS = sizeof parser / sizeof parser[0];
@@ -1468,18 +1477,23 @@ static void textview_make_clickable_parts_later(TextView *textview,
offset = gtk_text_iter_get_offset(&start_iter);
/* parse for clickable parts, and build a list of begin and end positions */
+ mybuf_len = strlen(mybuf);
for (n = 0; n < PARSE_ELEMS; n++) {
+ gint len = mybuf_len;
+ gint needle_len = strlen(parser[n].needle);
for (walk = mybuf;;) {
- gchar *scanpos = parser[n].search(walk, parser[n].needle);
+ gchar *scanpos = parser[n].search(walk, len, parser[n].needle);
if (scanpos) {
/* check if URI can be parsed */
if (parser[n].parse(walk, scanpos, &bp, &ep, FALSE)
- && (size_t) (ep - bp - 1) > strlen(parser[n].needle)) {
+ && (size_t) (ep - bp - 1) > needle_len) {
ADD_TXT_POS_LATER(bp, ep, n);
+ len -= ep - walk;
walk = ep;
- } else
- walk = scanpos +
- strlen(parser[n].needle);
+ } else {
+ len -= (scanpos + needle_len) - walk;
+ walk = scanpos + needle_len;
+ }
} else
break;
}
--
1.7.11.7
More information about the Users
mailing list