drw: minor improvement to the nomatches cache - dmenu - dynamic menu | |
git clone git://git.suckless.org/dmenu | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 7ab0cb5ef0e19352fc5d64ae0d57a5cf4540acbf | |
parent 0fe460dbd469a1d5b6a7140d0e1801935e4a923b | |
Author: NRK <[email protected]> | |
Date: Fri, 7 Jul 2023 17:00:42 +0600 | |
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. | |
Diffstat: | |
M dmenu.c | 1 - | |
M drw.c | 23 ++++++++++++----------- | |
M util.h | 1 + | |
3 files changed, 13 insertions(+), 12 deletions(-) | |
--- | |
diff --git 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(… | |
* MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX(… | |
-#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 | |
@@ -238,8 +238,8 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned i… | |
int | |
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int … | |
{ | |
- 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 i… | |
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; } nom… | |
- 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… | |
* character must be drawn. */ | |
charexists = 1; | |
- for (i = 0; i < nomatches_len; ++i) { | |
- /* avoid calling XftFontMatch if we know we wo… | |
- 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 w… | |
+ if (nomatches[h0] == utf8codepoint || nomatches[h1] ==… | |
+ goto no_match; | |
fccharset = FcCharSetCreate(); | |
FcCharSetAddChar(fccharset, utf8codepoint); | |
@@ -371,7 +372,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned i… | |
curfont->next = usedfont; | |
} else { | |
xfont_free(usedfont); | |
- nomatches.codepoint[++nomatches.idx % … | |
+ nomatches[nomatches[h0] ? h1 : h0] = u… | |
no_match: | |
usedfont = drw->fonts; | |
} | |
diff --git 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); |