commit a40588e25fabcfe13c8984486f17cc58eecc7f79
parent 24c205e7ad78c776b1a89cb0582f4f2c2ab473ab
Author: Colin Leroy <colin@colino.net>
Date: Thu, 25 Oct 2012 07:45:01 +0000
2012-10-25 [colin] 3.8.1cvs106
* src/common/utils.c
* src/common/utils.h
* src/textview.c
Avoid strlen() on inner loop in textview_make_clickable_parts*()
reduces cost of strcasestr() in textview_make_clickable_parts*()
from 30% to 15%. Patch by Igor Mammedov
Diffstat:
6 files changed, 64 insertions(+), 31 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1,3 +1,12 @@
+2012-10-25 [colin] 3.8.1cvs106
+
+ * src/common/utils.c
+ * src/common/utils.h
+ * src/textview.c
+ Avoid strlen() on inner loop in textview_make_clickable_parts*()
+ reduces cost of strcasestr() in textview_make_clickable_parts*()
+ from 30% to 15%. Patch by Igor Mammedov
+
2012-10-25 [colin] 3.8.1cvs105
* src/textview.c
diff --git a/PATCHSETS b/PATCHSETS
@@ -4480,3 +4480,4 @@
( cvs diff -u -r 1.1.2.6 -r 1.1.2.7 src/advsearch.c; ) > 3.8.1cvs103.patchset
( cvs diff -u -r 1.100.2.85 -r 1.100.2.86 AUTHORS; cvs diff -u -r 1.96.2.249 -r 1.96.2.250 src/textview.c; cvs diff -u -r 1.12.2.35 -r 1.12.2.36 src/textview.h; cvs diff -u -r 1.1.2.81 -r 1.1.2.82 src/gtk/authors.h; ) > 3.8.1cvs104.patchset
( cvs diff -u -r 1.96.2.250 -r 1.96.2.251 src/textview.c; ) > 3.8.1cvs105.patchset
+( cvs diff -u -r 1.36.2.207 -r 1.36.2.208 src/common/utils.c; cvs diff -u -r 1.20.2.82 -r 1.20.2.83 src/common/utils.h; cvs diff -u -r 1.96.2.251 -r 1.96.2.252 src/textview.c; ) > 3.8.1cvs106.patchset
diff --git a/configure.ac b/configure.ac
@@ -12,7 +12,7 @@ MINOR_VERSION=8
MICRO_VERSION=1
INTERFACE_AGE=0
BINARY_AGE=0
-EXTRA_VERSION=105
+EXTRA_VERSION=106
EXTRA_RELEASE=
EXTRA_GTK2_VERSION=
diff --git a/src/common/utils.c b/src/common/utils.c
@@ -534,9 +534,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
@@ -309,6 +309,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
@@ -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;
}