Skip to content

Commit c0733fb

Browse files
committed
strings even faster
1 parent af21ff9 commit c0733fb

File tree

1 file changed

+80
-7
lines changed

1 file changed

+80
-7
lines changed

src/jsony.nim

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,7 @@ proc parseHook*(s: string, i: var int, v: var SomeFloat) =
127127
i += chars
128128
v = f
129129

130-
proc parseHook*(s: string, i: var int, v: var string) =
131-
## Parse string.
132-
eatSpace(s, i)
133-
if i + 3 < s.len and s[i+0] == 'n' and s[i+1] == 'u' and s[i+2] == 'l' and s[i+3] == 'l':
134-
i += 4
135-
return
136-
eatChar(s, i, '"')
130+
proc parseStringSlow(s: string, i: var int, v: var string) =
137131
while i < s.len:
138132
let c = s[i]
139133
case c
@@ -161,6 +155,85 @@ proc parseHook*(s: string, i: var int, v: var string) =
161155
inc i
162156
eatChar(s, i, '"')
163157

158+
proc parseStringFast(s: string, i: var int, v: var string) =
159+
# It appears to be faster to scan the string once, then allocate exact chars,
160+
# and then scan the string again populating it.
161+
var
162+
j = i
163+
ll = 0
164+
while j < s.len:
165+
let c = s[j]
166+
case c
167+
of '"':
168+
break
169+
of '\\':
170+
inc j
171+
let c = s[j]
172+
case c
173+
of 'u':
174+
inc j
175+
let u = parseHexInt(s[j ..< j + 4])
176+
j += 3
177+
ll += Rune(u).toUTF8().len
178+
else:
179+
inc ll
180+
else:
181+
inc ll
182+
inc j
183+
184+
if ll > 0:
185+
v = newString(ll)
186+
var
187+
at = 0
188+
ss = cast[ptr UncheckedArray[char]](v[0].addr)
189+
template add(ss: ptr UncheckedArray[char], c: char) =
190+
ss[at] = c
191+
inc at
192+
while i < s.len:
193+
let c = s[i]
194+
case c
195+
of '"':
196+
break
197+
of '\\':
198+
inc i
199+
let c = s[i]
200+
case c
201+
of '"', '\\', '/': ss.add(c)
202+
of 'b': ss.add '\b'
203+
of 'f': ss.add '\f'
204+
of 'n': ss.add '\n'
205+
of 'r': ss.add '\r'
206+
of 't': ss.add '\t'
207+
of 'u':
208+
inc i
209+
let u = parseHexInt(s[i ..< i + 4])
210+
i += 3
211+
for c in Rune(u).toUTF8():
212+
ss.add(c)
213+
else:
214+
ss.add(c)
215+
else:
216+
ss.add(c)
217+
inc i
218+
219+
eatChar(s, i, '"')
220+
221+
proc parseHook*(s: string, i: var int, v: var string) =
222+
## Parse string.
223+
eatSpace(s, i)
224+
if i + 3 < s.len and s[i+0] == 'n' and s[i+1] == 'u' and s[i+2] == 'l' and s[i+3] == 'l':
225+
i += 4
226+
return
227+
eatChar(s, i, '"')
228+
229+
when nimvm:
230+
parseStringSlow(s, i, v)
231+
else:
232+
when defined(js):
233+
parseStringSlow(s, i, v)
234+
else:
235+
parseStringFast(s, i, v)
236+
164237
proc parseHook*(s: string, i: var int, v: var char) =
165238
var str: string
166239
s.parseHook(i, str)

0 commit comments

Comments
 (0)