From 9819209e530fb943e7ba9a3d46ed25a01880de17 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 8 Dec 2023 17:56:45 +0000 Subject: [PATCH] Bodgy fix for poor performance of wcwidth. Mastodonochrome was running rather slowly, and when I profiled it, it turned out the bottleneck was the 'wcwidth' Python module, which is not a wrapper on the C function, but a reimplementation in pure Python and therefore not very fast. I've bodged it by just making one big cache of all the strings that the program ever passes to wcwidth, since there were only two calls to that function at all and they were both in text.py. I don't know if that's the right fix in the long term, but it seems to have improved things considerably for now. (Also, while I'm at it, ColouredString now wcwidths its contents once at construction time and doesn't redo it on every call, so it doesn't even look up the same thing in the cache multiple times.) --- text.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/text.py b/text.py index c0cd566..de68152 100644 --- a/text.py +++ b/text.py @@ -35,6 +35,12 @@ colourmap = { '-': [0, 7, 40, 36], # separator line between editor header and content } +wcswidth_cache = {} +def cached_wcswidth(s): + if s not in wcswidth_cache: + wcswidth_cache[s] = wcwidth.wcswidth(s) + return wcswidth_cache[s] + class ColouredString: def __init__(self, string, colour=' '): if isinstance(string, ColouredString): @@ -44,6 +50,7 @@ class ColouredString: assert len(colour) == 1, "Colour ids are single characters" colour = colour * len(string) self.s, self.c = string, colour + self.width = cached_wcswidth(self.s) def __add__(self, rhs): rhs = type(self)(rhs) @@ -55,10 +62,6 @@ class ColouredString: def __len__(self): return len(self.s) - @property - def width(self): - return wcwidth.wcswidth(self.s) - def __str__(self): return self.s @@ -97,7 +100,7 @@ class ColouredString: colour = self.c[pos] fraglen = len(self.c) - pos - len(self.c[pos:].lstrip(colour)) frag = self.s[pos:pos+fraglen] - yield frag, colour, wcwidth.wcswidth(frag) + yield frag, colour, cached_wcswidth(frag) pos += fraglen def split(self, width): -- 2.30.2