[gtksourceview] utils: avoid use of rodata for string conversion speedup



commit b8229fc63533b3cfecddb046ffc5c3b644bbe184
Author: Christian Hergert <chergert redhat com>
Date:   Thu Apr 18 17:25:08 2019 -0700

    utils: avoid use of rodata for string conversion speedup
    
    The rodata version is faster, but this version is close enough that it
    warrants not having the large amount of rodata included in the overhead.
    
    This caches the previously generated string and tries to handle the common
    case of sequential printf() by incrementing the last character. If that
    overflows, we walk towards the start of the string until we do not need
    to overflow.
    
    This is still roughly 20x faster than using sprintf() directly, as we did
    previously, for sequential strings.

 gtksourceview/Makefile.am                    |    1 -
 gtksourceview/gtksourcegutterrendererlines.c |    2 +-
 gtksourceview/gtksourcenumbers-private.h     | 1262 --------------------------
 gtksourceview/gtksourceutils-private.h       |    3 +-
 gtksourceview/gtksourceutils.c               |   97 +-
 5 files changed, 54 insertions(+), 1311 deletions(-)
---
diff --git a/gtksourceview/Makefile.am b/gtksourceview/Makefile.am
index 8a4ca3ad..02a1aeac 100644
--- a/gtksourceview/Makefile.am
+++ b/gtksourceview/Makefile.am
@@ -117,7 +117,6 @@ libgtksourceview_private_headers =          \
        gtksourceiter.h                         \
        gtksourcelanguage-private.h             \
        gtksourcemarkssequence.h                \
-       gtksourcenumbers-private.h              \
        gtksourcepixbufhelper.h                 \
        gtksourceregex.h                        \
        gtksourcespacedrawer-private.h          \
diff --git a/gtksourceview/gtksourcegutterrendererlines.c b/gtksourceview/gtksourcegutterrendererlines.c
index 8df6c7d0..7c5b3020 100644
--- a/gtksourceview/gtksourcegutterrendererlines.c
+++ b/gtksourceview/gtksourcegutterrendererlines.c
@@ -229,7 +229,7 @@ gutter_renderer_query_data (GtkSourceGutterRenderer      *renderer,
 
        if G_LIKELY (!current_line)
        {
-               len = _gtk_source_utils_int_to_string (line, &textptr, text);
+               len = _gtk_source_utils_int_to_string (line, &textptr);
        }
        else
        {
diff --git a/gtksourceview/gtksourceutils-private.h b/gtksourceview/gtksourceutils-private.h
index 3f3e10db..217c38cd 100644
--- a/gtksourceview/gtksourceutils-private.h
+++ b/gtksourceview/gtksourceutils-private.h
@@ -41,8 +41,7 @@ gint          _gtk_source_utils_string_to_int                 (const gchar *str);
 
 G_GNUC_INTERNAL
 gint           _gtk_source_utils_int_to_string                 (guint         value,
-                                                                const gchar **outstr,
-                                                                gchar         tmpbuf[static 12]);
+                                                                const gchar **outstr);
 
 G_GNUC_INTERNAL
 gchar *                _gtk_source_utils_pango_font_description_to_css (const PangoFontDescription 
*font_desc);
diff --git a/gtksourceview/gtksourceutils.c b/gtksourceview/gtksourceutils.c
index 4601e895..8bc2d0ef 100644
--- a/gtksourceview/gtksourceutils.c
+++ b/gtksourceview/gtksourceutils.c
@@ -35,7 +35,6 @@
 
 #include "gtksourceutils.h"
 #include "gtksourceutils-private.h"
-#include "gtksourcenumbers-private.h"
 #include <string.h>
 #include <errno.h>
 #include <math.h>
@@ -520,69 +519,77 @@ _gtk_source_utils_dgettext (const gchar *domain,
  * _gtk_source_utils_int_to_string:
  * @value: the integer to convert to a string
  * @outstr: (out): a location for a pointer to the result string
- * @tmpbuf: scratch space that may be used to generate the string
  *
- * This function provides a fast path for converting line numbers to
- * their string equivalent without the use of snprintf() in all cases
- * from 0 to 20,000. This is useful when performing lots of string
- * conversions such as for line numbers in the text gutter.
+ * The following implementation uses an internal cache to speed up the
+ * conversion of integers to strings by comparing the value to the
+ * previous value that was calculated.
  *
- * If the line number is > 20,000, then @tmpbuf will be used along with
- * snprintf() to generate the string and @outstr will be set to @tmpbuf.
+ * If we detect a simple increment, we can alter the previous string directly
+ * and then carry the number to each of the previous chars sequentually. If we
+ * still have a carry bit at the end of the loop, we need to move the whole
+ * string over 1 place to take account for the new "1" at the start.
  *
- * In most cases, this will return a pointer to a string in the text
- * section of the library. Not all values are stored from 0 to 20,000,
- * only from 10,000 to 20,000. In cases < 10,000, we use an offset of
- * the string within the first 10,000 adjusted to look like the expected
- * number.
+ * This function is not thread-safe, as the resulting string is stored in
+ * static data.
  *
  * Returns: the number of characters in the resulting string
  */
 gint
 _gtk_source_utils_int_to_string (guint         value,
-                                 const gchar **outstr,
-                                 gchar         tmpbuf[static 12])
+                                 const gchar **outstr)
 {
-       gint ret;
+       static struct{
+               guint value;
+               guint len;
+               gchar str[12];
+       } fi;
 
-       /* The first offset is 10,000 so we can use that string but offset
-        * ourselves into that string a bit to get the same number we would
-        * if we had smaller strings available.
-        */
+       *outstr = fi.str;
 
-       if (value < 10)
+       if (value == fi.value)
        {
-               *outstr = gtk_source_numbers[value] + 4;
-               return 1;
+               return fi.len;
        }
 
-       if (value < 100)
+       if G_LIKELY (value == fi.value + 1)
        {
-               *outstr = gtk_source_numbers[value] + 3;
-               return 2;
-       }
+               guint carry = 1;
 
-       if (value < 1000)
-       {
-               *outstr = gtk_source_numbers[value] + 2;
-               return 3;
-       }
+               for (gint i = fi.len - 1; i >= 0; i--)
+               {
+                       fi.str[i] += carry;
+                       carry = fi.str[i] == ':';
 
-       if (value < 10000)
-       {
-               *outstr = gtk_source_numbers[value] + 1;
-               return 4;
-       }
+                       if (carry)
+                       {
+                               fi.str[i] = '0';
+                       }
+                       else
+                       {
+                               break;
+                       }
+               }
 
-       if (value < 20000)
-       {
-               *outstr = gtk_source_numbers[value - 10000];
-               return 5;
+               if G_UNLIKELY (carry)
+               {
+                       for (guint i = fi.len; i > 0; i--)
+                       {
+                               fi.str[i] = fi.str[i-1];
+                       }
+
+                       fi.len++;
+                       fi.str[0] = '1';
+                       fi.str[fi.len] = 0;
+               }
+
+               fi.value++;
+
+               return fi.len;
        }
 
-       *outstr = tmpbuf;
-       ret = snprintf (tmpbuf, 12, "%u", value);
-       tmpbuf[11] = 0;
+       fi.len = snprintf (fi.str, sizeof fi.str - 1, "%u", value);
+       fi.str[fi.len] = 0;
+       fi.value = value;
 
-       return ret;
+       return fi.len;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]