Skip to content

Commit f7d7a24

Browse files
committed
Speed up String encoding on CPUs without SIMD hardware support
This change tests for the presence of characters to be escaped on CPUs without special SIMD instructions. We are testing 8 chars in one round, following a code excerpt from https://lemire.me/blog/2025/04/13/detect-control-characters-quotes-and-backslashes-efficiently-using-swar/ For strings that don't require escapes I have seen speedups of around 15% with this change.
1 parent a29cb77 commit f7d7a24

1 file changed

Lines changed: 17 additions & 0 deletions

File tree

ext/json/ext/generator/generator.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,25 @@ static const unsigned char escape_table_basic[256] = {
162162

163163
static unsigned char (*search_escape_basic_impl)(search_state *);
164164

165+
inline bool has_json_escapable_byte(uint64_t x) {
166+
uint64_t is_ascii = 0x8080808080808080ULL & ~x;
167+
uint64_t xor2 = x ^ 0x0202020202020202ULL;
168+
uint64_t lt32_or_eq34 = xor2 - 0x2121212121212121ULL;
169+
uint64_t sub92 = x ^ 0x5C5C5C5C5C5C5C5CULL;
170+
uint64_t eq92 = (sub92 - 0x0101010101010101ULL);
171+
return ((lt32_or_eq34 | eq92) & is_ascii) != 0;
172+
}
173+
165174
static inline unsigned char search_escape_basic(search_state *search)
166175
{
176+
while (search->ptr <= search->end - 8) {
177+
uint64_t* pi = (uint64_t*)(search->ptr);
178+
if(has_json_escapable_byte(*pi)) {
179+
break;
180+
}
181+
search->ptr += 8;
182+
}
183+
167184
while (search->ptr < search->end) {
168185
if (RB_UNLIKELY(escape_table_basic[(const unsigned char)*search->ptr])) {
169186
search_flush(search);

0 commit comments

Comments
 (0)