summaryrefslogtreecommitdiffstats
path: root/src/bfstd.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2023-08-07 19:41:12 -0400
committerTavian Barnes <tavianator@tavianator.com>2023-08-07 19:41:38 -0400
commit2bc5a379b5f4f6a35465a2df19107209ed191d06 (patch)
treef38dcb368af2650a537aad5e890fc0ee64f15a6d /src/bfstd.c
parent39baf8a76ddefe3a9f02fc1170b213939ab2d5c2 (diff)
downloadbfs-2bc5a379b5f4f6a35465a2df19107209ed191d06.tar.xz
bfstd: Check multiple chars at once for isascii()
Diffstat (limited to 'src/bfstd.c')
-rw-r--r--src/bfstd.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/src/bfstd.c b/src/bfstd.c
index 9cfd09c..a71e4b4 100644
--- a/src/bfstd.c
+++ b/src/bfstd.c
@@ -639,17 +639,34 @@ static size_t printable_len(const char *str, size_t len, enum wesc_flags flags)
call_once(&once, char_cache_init);
// Fast path: avoid multibyte checks
- size_t i;
- for (i = 0; i < len; ++i) {
+ size_t i, word;
+ for (i = 0; i + sizeof(word) <= len;) {
+ // Word-at-a-time isascii()
+ memcpy(&word, str + i, sizeof(word));
+ // 0xFFFF... / 0xFF == 0x10101...
+ size_t mask = (SIZE_MAX / 0xFF) << 7;
+ if (word & mask) {
+ goto multibyte;
+ }
+
+ for (size_t j = 0; j < sizeof(word); ++i, ++j) {
+ if (!xisprint(str[i], flags)) {
+ return i;
+ }
+ }
+ }
+
+ for (; i < len; ++i) {
unsigned char c = str[i];
if (!isascii(c)) {
- break;
+ goto multibyte;
}
if (!xisprint(c, flags)) {
return i;
}
}
+multibyte:
mbstate_t mb;
memset(&mb, 0, sizeof(mb));