significantly improve performance on large strings - dmenu - dynamic menu
 (HTM) git clone git://git.suckless.org/dmenu
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 7269c5355d257dd2ad2c53f15dc9c1cf6796aea5
 (DIR) parent 6be057f060543bb0f3ed9423904263617cdffffe
 (HTM) Author: NRK <nrk@disroot.org>
       Date:   Thu, 24 Mar 2022 02:04:04 +0600
       
       significantly improve performance on large strings
       
       this replaces inefficient pattern of `MIN(TEXTW(..), n)` with
       drw_fontset_getwidth_clamp() instead, which is far more efficient when
       we only want up to a certain width.
       
       dumping a decently sized (unicode) emoji file into dmenu, I see the
       startup time drop significantly with this patch.
       
       before -> after
       360ms  -> 160ms
       
       this should also noticeably improve input latency (responsiveness) given
       that calcoffsets() and drawmenu() are pretty hot functions.
       
       Diffstat:
         M dmenu.c                             |      13 ++++++++++---
       
       1 file changed, 10 insertions(+), 3 deletions(-)
       ---
 (DIR) diff --git a/dmenu.c b/dmenu.c
       @@ -58,6 +58,13 @@ static Clr *scheme[SchemeLast];
        static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
        static char *(*fstrstr)(const char *, const char *) = strstr;
        
       +static unsigned int
       +textw_clamp(const char *str, unsigned int n)
       +{
       +        unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad;
       +        return MIN(w, n);
       +}
       +
        static void
        appenditem(struct item *item, struct item **list, struct item **last)
        {
       @@ -82,10 +89,10 @@ calcoffsets(void)
                        n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
                /* calculate which items will begin the next page and previous page */
                for (i = 0, next = curr; next; next = next->right)
       -                if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n)
       +                if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n)
                                break;
                for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
       -                if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n)
       +                if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n)
                                break;
        }
        
       @@ -172,7 +179,7 @@ drawmenu(void)
                        }
                        x += w;
                        for (item = curr; item != next; item = item->right)
       -                        x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">")));
       +                        x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">")));
                        if (next) {
                                w = TEXTW(">");
                                drw_setscheme(drw, scheme[SchemeNorm]);