Skip to content

Commit 8395736

Browse files
authored
Merge pull request #1562 from fsprojects/daily-perf-improver-json-serialization
Daily Perf Improver: Optimize JSON string serialization performance
2 parents 476fb43 + cdd72a4 commit 8395736

File tree

1 file changed

+39
-12
lines changed

1 file changed

+39
-12
lines changed

src/FSharp.Data.Json.Core/JsonValue.fs

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,26 +125,53 @@ type JsonValue =
125125

126126
serialize 0 x
127127

128+
// Optimized JSON string encoding with reduced allocations and bulk writing
128129
// Encode characters that are not valid in JS string. The implementation is based
129130
// on https://github.com/mono/mono/blob/master/mcs/class/System.Web/System.Web/HttpUtility.cs
130131
static member internal JsonStringEncodeTo (w: TextWriter) (value: string) =
131132
if not (String.IsNullOrEmpty value) then
133+
let mutable lastWritePos = 0
134+
132135
for i = 0 to value.Length - 1 do
133136
let c = value.[i]
134137
let ci = int c
135138

136-
if ci >= 0 && ci <= 7 || ci = 11 || ci >= 14 && ci <= 31 then
137-
w.Write("\\u{0:x4}", ci) |> ignore
138-
else
139-
match c with
140-
| '\b' -> w.Write "\\b"
141-
| '\t' -> w.Write "\\t"
142-
| '\n' -> w.Write "\\n"
143-
| '\f' -> w.Write "\\f"
144-
| '\r' -> w.Write "\\r"
145-
| '"' -> w.Write "\\\""
146-
| '\\' -> w.Write "\\\\"
147-
| _ -> w.Write c
139+
let needsEscaping =
140+
ci >= 0 && ci <= 7
141+
|| ci = 11
142+
|| ci >= 14 && ci <= 31
143+
|| c = '\b'
144+
|| c = '\t'
145+
|| c = '\n'
146+
|| c = '\f'
147+
|| c = '\r'
148+
|| c = '"'
149+
|| c = '\\'
150+
151+
if needsEscaping then
152+
// Write all accumulated unescaped characters in one operation using Substring
153+
if i > lastWritePos then
154+
w.Write(value.Substring(lastWritePos, i - lastWritePos))
155+
156+
// Write the escaped character
157+
if ci >= 0 && ci <= 7 || ci = 11 || ci >= 14 && ci <= 31 then
158+
w.Write("\\u{0:x4}", ci) |> ignore
159+
else
160+
match c with
161+
| '\b' -> w.Write "\\b"
162+
| '\t' -> w.Write "\\t"
163+
| '\n' -> w.Write "\\n"
164+
| '\f' -> w.Write "\\f"
165+
| '\r' -> w.Write "\\r"
166+
| '"' -> w.Write "\\\""
167+
| '\\' -> w.Write "\\\\"
168+
| _ -> w.Write c
169+
170+
lastWritePos <- i + 1
171+
172+
// Write any remaining unescaped characters
173+
if lastWritePos < value.Length then
174+
w.Write(value.Substring(lastWritePos))
148175

149176
member x.ToString(saveOptions, ?indentationSpaces: int) =
150177
let w = new StringWriter(CultureInfo.InvariantCulture)

0 commit comments

Comments
 (0)