]> Skullheadx's Git Forge - dmenu.git/commitdiff
drw: minor improvement to the nomatches cache
authorNRK <nrk@disroot.org>
Fri, 7 Jul 2023 11:00:42 +0000 (17:00 +0600)
committerHiltjo Posthuma <hiltjo@codemadness.org>
Fri, 7 Jul 2023 13:03:57 +0000 (15:03 +0200)
1. use `unsigned int` to store the codepoints, this avoids waste on
   common case where `long` is 64bits. and POSIX guarantees `int` to be
   at least 32bits so there's no risk of truncation.
2. since switching to `unsigned int` cuts down the memory requirement by
   half, double the cache size from 64 to 128.
3. instead of a linear search, use a simple hash-table for O(1) lookups.

dmenu.c
drw.c
util.h

diff --git a/dmenu.c b/dmenu.c
index 62f1089ff4f414c6ccdfc85e07eedbb706aec562..40f93e02394d94c79361761f46045cb676948db5 100644 (file)
--- a/dmenu.c
+++ b/dmenu.c
@@ -22,7 +22,6 @@
 /* macros */
 #define INTERSECT(x,y,w,h,r)  (MAX(0, MIN((x)+(w),(r).x_org+(r).width)  - MAX((x),(r).x_org)) \
                              * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org)))
-#define LENGTH(X)             (sizeof X / sizeof X[0])
 #define TEXTW(X)              (drw_fontset_getwidth(drw, (X)) + lrpad)
 
 /* enums */
diff --git a/drw.c b/drw.c
index a58a2b4896500cd7c3b61fbdc626cd42cd9df40e..78a2b27211ab59ad312efbb11e1a0c5146e09555 100644 (file)
--- a/drw.c
+++ b/drw.c
@@ -238,8 +238,8 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int
 int
 drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
 {
-       int i, ty, ellipsis_x = 0;
-       unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len;
+       int ty, ellipsis_x = 0;
+       unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, hash, h0, h1;
        XftDraw *d = NULL;
        Fnt *usedfont, *curfont, *nextfont;
        int utf8strlen, utf8charlen, render = x || y || w || h;
@@ -251,9 +251,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
        XftResult result;
        int charexists = 0, overflow = 0;
        /* keep track of a couple codepoints for which we have no match. */
-       enum { nomatches_len = 64 };
-       static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches;
-       static unsigned int ellipsis_width = 0;
+       static unsigned int nomatches[128], ellipsis_width;
 
        if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
                return 0;
@@ -338,11 +336,14 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
                         * character must be drawn. */
                        charexists = 1;
 
-                       for (i = 0; i < nomatches_len; ++i) {
-                               /* avoid calling XftFontMatch if we know we won't find a match */
-                               if (utf8codepoint == nomatches.codepoint[i])
-                                       goto no_match;
-                       }
+                       hash = (unsigned int)utf8codepoint;
+                       hash = ((hash >> 16) ^ hash) * 0x21F0AAAD;
+                       hash = ((hash >> 15) ^ hash) * 0xD35A2D97;
+                       h0 = ((hash >> 15) ^ hash) % LENGTH(nomatches);
+                       h1 = (hash >> 17) % LENGTH(nomatches);
+                       /* avoid expensive XftFontMatch call when we know we won't find a match */
+                       if (nomatches[h0] == utf8codepoint || nomatches[h1] == utf8codepoint)
+                               goto no_match;
 
                        fccharset = FcCharSetCreate();
                        FcCharSetAddChar(fccharset, utf8codepoint);
@@ -371,7 +372,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
                                        curfont->next = usedfont;
                                } else {
                                        xfont_free(usedfont);
-                                       nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint;
+                                       nomatches[nomatches[h0] ? h1 : h0] = utf8codepoint;
 no_match:
                                        usedfont = drw->fonts;
                                }
diff --git a/util.h b/util.h
index f633b5173ad2b5058d48574d5a18fe3f135c4193..c0a50d4424b8a4167513d2f170fba1f5035df9ac 100644 (file)
--- a/util.h
+++ b/util.h
@@ -3,6 +3,7 @@
 #define MAX(A, B)               ((A) > (B) ? (A) : (B))
 #define MIN(A, B)               ((A) < (B) ? (A) : (B))
 #define BETWEEN(X, A, B)        ((A) <= (X) && (X) <= (B))
+#define LENGTH(X)               (sizeof (X) / sizeof (X)[0])
 
 void die(const char *fmt, ...);
 void *ecalloc(size_t nmemb, size_t size);