diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2023-08-07 18:29:19 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2023-08-07 18:43:40 -0400 |
commit | 39baf8a76ddefe3a9f02fc1170b213939ab2d5c2 (patch) | |
tree | 4692e02edda54a91a4af868f1c365842aba13c93 /src/bfstd.c | |
parent | 81dda3027c8e75a3e7988561614d153c888c046e (diff) | |
download | bfs-39baf8a76ddefe3a9f02fc1170b213939ab2d5c2.tar.xz |
bfstd: Speed up wordesc() by caching isprint()/isspace()
Diffstat (limited to 'src/bfstd.c')
-rw-r--r-- | src/bfstd.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/src/bfstd.c b/src/bfstd.c index 49c4a70..9cfd09c 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -5,6 +5,7 @@ #include "bit.h" #include "config.h" #include "diag.h" +#include "thread.h" #include "xregex.h" #include <ctype.h> #include <errno.h> @@ -580,16 +581,39 @@ size_t xstrwidth(const char *str) { return ret; } +/** + * Character type flags. + */ +enum ctype { + IS_PRINT = 1 << 0, + IS_SPACE = 1 << 1, +}; + +/** Cached ctypes. */ +static unsigned char ctype_cache[UCHAR_MAX + 1]; + +/** Initialize the ctype cache. */ +static void char_cache_init(void) { + for (size_t c = 0; c <= UCHAR_MAX; ++c) { + if (isprint(c)) { + ctype_cache[c] |= IS_PRINT; + } + if (isspace(c)) { + ctype_cache[c] |= IS_SPACE; + } + } +} + /** Check if a character is printable. */ static bool xisprint(unsigned char c, enum wesc_flags flags) { - if (isprint(c)) { + if (ctype_cache[c] & IS_PRINT) { return true; } // Technically a literal newline is safe inside single quotes, but $'\n' // is much nicer than ' // ' - if (!(flags & WESC_SHELL) && isspace(c)) { + if (!(flags & WESC_SHELL) && (ctype_cache[c] & IS_SPACE)) { return true; } @@ -611,6 +635,9 @@ static bool xiswprint(wchar_t c, enum wesc_flags flags) { /** Get the length of the longest printable prefix of a string. */ static size_t printable_len(const char *str, size_t len, enum wesc_flags flags) { + static pthread_once_t once = PTHREAD_ONCE_INIT; + call_once(&once, char_cache_init); + // Fast path: avoid multibyte checks size_t i; for (i = 0; i < len; ++i) { |