From 76549d014ef6abdecb1d676e5d4de160f86ba2d9 Mon Sep 17 00:00:00 2001 From: bakkeby Date: Fri, 22 Sep 2023 18:24:09 +0200 Subject: [PATCH] drw: minor improvement to the nomatches cache 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. ref. https://git.suckless.org/dmenu/commit/7ab0cb5ef0e19352fc5d64ae0d57a5cf4540acbf.html --- README.md | 4 ++-- dmenu.c | 1 - drw.c | 23 ++++++++++++----------- util.h | 1 + 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index be2c349..9e1bff7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -Similar to [dwm-flexipatch](https://github.com/bakkeby/dwm-flexipatch) this dmenu 5.2 (0fe460d, -2023-04-05) project has a different take on patching. It uses preprocessor directives to decide +Similar to [dwm-flexipatch](https://github.com/bakkeby/dwm-flexipatch) this dmenu 5.2 (8df553e, +2023-09-22) project has a different take on patching. It uses preprocessor directives to decide whether or not to include a patch during build time. Essentially this means that this build, for better or worse, contains both the patched _and_ the original code. The aim being that you can select which patches to include and the build will contain that code and nothing more. diff --git a/dmenu.c b/dmenu.c index 5d20ed8..0bcafd1 100644 --- a/dmenu.c +++ b/dmenu.c @@ -33,7 +33,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]) #if PANGO_PATCH #define TEXTW(X) (drw_font_getwidth(drw, (X), False) + lrpad) #define TEXTWM(X) (drw_font_getwidth(drw, (X), True) + lrpad) diff --git a/drw.c b/drw.c index 62096d1..41857e5 100644 --- a/drw.c +++ b/drw.c @@ -430,8 +430,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp 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; @@ -443,10 +443,8 @@ 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 nomatches[128], ellipsis_width; const char *ellipsis = "..."; - static unsigned int ellipsis_width = 0; if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) return 0; @@ -535,11 +533,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); @@ -571,7 +572,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 531ab25..2922d77 100644 --- a/util.h +++ b/util.h @@ -7,6 +7,7 @@ #define MIN(A, B) ((A) < (B) ? (A) : (B)) #endif #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);