Skip to content

Commit be9d9c7

Browse files
larubujoRX14
authored andcommittedJan 2, 2018
Optimize String#to_json (#5456)
1 parent a3f2ecc commit be9d9c7

File tree

2 files changed

+41
-10
lines changed

2 files changed

+41
-10
lines changed
 

‎spec/std/json/serialization_spec.cr

+13
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,19 @@ describe "JSON serialization" do
215215
"\u{19}".to_json.should eq("\"\\u0019\"")
216216
end
217217

218+
it "does for String with control codes in a few places" do
219+
"\fab".to_json.should eq(%q("\fab"))
220+
"ab\f".to_json.should eq(%q("ab\f"))
221+
"ab\fcd".to_json.should eq(%q("ab\fcd"))
222+
"ab\fcd\f".to_json.should eq(%q("ab\fcd\f"))
223+
"ab\fcd\fe".to_json.should eq(%q("ab\fcd\fe"))
224+
"\u{19}ab".to_json.should eq(%q("\u0019ab"))
225+
"ab\u{19}".to_json.should eq(%q("ab\u0019"))
226+
"ab\u{19}cd".to_json.should eq(%q("ab\u0019cd"))
227+
"ab\u{19}cd\u{19}".to_json.should eq(%q("ab\u0019cd\u0019"))
228+
"ab\u{19}cd\u{19}e".to_json.should eq(%q("ab\u0019cd\u0019e"))
229+
end
230+
218231
it "does for Array" do
219232
[1, 2, 3].to_json.should eq("[1,2,3]")
220233
end

‎src/json/builder.cr

+28-10
Original file line numberDiff line numberDiff line change
@@ -94,35 +94,53 @@ class JSON::Builder
9494
# This method can also be used to write the name of an object field.
9595
def string(value)
9696
string = value.to_s
97+
9798
scalar(string: true) do
9899
io << '"'
99-
string.each_char do |char|
100-
case char
100+
101+
start_pos = 0
102+
reader = Char::Reader.new(string)
103+
104+
while reader.has_next?
105+
case char = reader.current_char
101106
when '\\'
102-
io << "\\\\"
107+
escape = "\\\\"
103108
when '"'
104-
io << "\\\""
109+
escape = "\\\""
105110
when '\b'
106-
io << "\\b"
111+
escape = "\\b"
107112
when '\f'
108-
io << "\\f"
113+
escape = "\\f"
109114
when '\n'
110-
io << "\\n"
115+
escape = "\\n"
111116
when '\r'
112-
io << "\\r"
117+
escape = "\\r"
113118
when '\t'
114-
io << "\\t"
119+
escape = "\\t"
115120
when .ascii_control?
121+
io.write string.to_slice[start_pos, reader.pos - start_pos]
116122
io << "\\u"
117123
ord = char.ord
118124
io << '0' if ord < 0x1000
119125
io << '0' if ord < 0x100
120126
io << '0' if ord < 0x10
121127
ord.to_s(16, io)
128+
reader.next_char
129+
start_pos = reader.pos
130+
next
122131
else
123-
io << char
132+
reader.next_char
133+
next
124134
end
135+
136+
io.write string.to_slice[start_pos, reader.pos - start_pos]
137+
io << escape
138+
reader.next_char
139+
start_pos = reader.pos
125140
end
141+
142+
io.write string.to_slice[start_pos, reader.pos - start_pos]
143+
126144
io << '"'
127145
end
128146
end

0 commit comments

Comments
 (0)
Please sign in to comment.