summaryrefslogtreecommitdiffstats
path: root/src/bfstd.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2023-08-07 18:29:19 -0400
committerTavian Barnes <tavianator@tavianator.com>2023-08-07 18:43:40 -0400
commit39baf8a76ddefe3a9f02fc1170b213939ab2d5c2 (patch)
tree4692e02edda54a91a4af868f1c365842aba13c93 /src/bfstd.c
parent81dda3027c8e75a3e7988561614d153c888c046e (diff)
downloadbfs-39baf8a76ddefe3a9f02fc1170b213939ab2d5c2.tar.xz
bfstd: Speed up wordesc() by caching isprint()/isspace()
Diffstat (limited to 'src/bfstd.c')
-rw-r--r--src/bfstd.c31
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) {