Skip to content

Commit b5797e8

Browse files
authored
Merge pull request #923 from ddunn2/jsonPerf
2 parents dcd7c82 + 313cc93 commit b5797e8

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

Foundation/NSJSONSerialization.swift

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ internal extension JSONSerialization {
284284
//MARK: - JSONSerializer
285285
private struct JSONWriter {
286286

287+
private let maxUIntLength = String(describing: UInt.max).characters.count
288+
private let maxIntLength = String(describing: Int.max).characters.count
287289
var indent = 0
288290
let pretty: Bool
289291
let writer: (String?) -> Void
@@ -309,6 +311,10 @@ private struct JSONWriter {
309311
try serializeString(str)
310312
case let boolValue as Bool:
311313
serializeBool(boolValue)
314+
case let num as Int:
315+
try serializeInt(value: num)
316+
case let num as UInt:
317+
try serializeUInt(value: num)
312318
case let array as Array<Any>:
313319
try serializeArray(array)
314320
case let dict as Dictionary<AnyHashable, Any>:
@@ -322,6 +328,92 @@ private struct JSONWriter {
322328
}
323329
}
324330

331+
private func serializeUInt(value: UInt) throws {
332+
if value == 0 {
333+
writer("0")
334+
return
335+
}
336+
var array: [UInt] = []
337+
var stringResult = ""
338+
//Maximum length of an UInt
339+
array.reserveCapacity(maxUIntLength)
340+
stringResult.reserveCapacity(maxUIntLength)
341+
var number = value
342+
343+
while number != 0 {
344+
array.append(number % 10)
345+
number /= 10
346+
}
347+
348+
/*
349+
Step backwards through the array and append the values to the string. This way the values are appended in the correct order.
350+
*/
351+
var counter = array.count
352+
while counter > 0 {
353+
counter -= 1
354+
let digit: UInt = array[counter]
355+
switch digit {
356+
case 0: stringResult.append("0")
357+
case 1: stringResult.append("1")
358+
case 2: stringResult.append("2")
359+
case 3: stringResult.append("3")
360+
case 4: stringResult.append("4")
361+
case 5: stringResult.append("5")
362+
case 6: stringResult.append("6")
363+
case 7: stringResult.append("7")
364+
case 8: stringResult.append("8")
365+
case 9: stringResult.append("9")
366+
default: fatalError()
367+
}
368+
}
369+
370+
writer(stringResult)
371+
}
372+
373+
private func serializeInt(value: Int) throws {
374+
if value == 0 {
375+
writer("0")
376+
return
377+
}
378+
var array: [Int] = []
379+
var stringResult = ""
380+
array.reserveCapacity(maxIntLength)
381+
//Account for a negative sign
382+
stringResult.reserveCapacity(maxIntLength + 1)
383+
var number = value
384+
385+
while number != 0 {
386+
array.append(number % 10)
387+
number /= 10
388+
}
389+
//If negative add minus sign before adding any values
390+
if value < 0 {
391+
stringResult.append("-")
392+
}
393+
/*
394+
Step backwards through the array and append the values to the string. This way the values are appended in the correct order.
395+
*/
396+
var counter = array.count
397+
while counter > 0 {
398+
counter -= 1
399+
let digit = array[counter]
400+
switch digit {
401+
case 0: stringResult.append("0")
402+
case 1, -1: stringResult.append("1")
403+
case 2, -2: stringResult.append("2")
404+
case 3, -3: stringResult.append("3")
405+
case 4, -4: stringResult.append("4")
406+
case 5, -5: stringResult.append("5")
407+
case 6, -6: stringResult.append("6")
408+
case 7, -7: stringResult.append("7")
409+
case 8, -8: stringResult.append("8")
410+
case 9, -9: stringResult.append("9")
411+
default: fatalError()
412+
}
413+
}
414+
writer(stringResult)
415+
}
416+
325417
func serializeString(_ str: String) throws {
326418
writer("\"")
327419
for scalar in str.unicodeScalars {

TestFoundation/TestNSJSONSerialization.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,10 @@ extension TestNSJSONSerialization {
863863
("test_nested_array", test_nested_array),
864864
("test_nested_dictionary", test_nested_dictionary),
865865
("test_serialize_number", test_serialize_number),
866+
("test_serialize_IntMax", test_serialize_IntMax),
867+
("test_serialize_IntMin", test_serialize_IntMin),
868+
("test_serialize_UIntMax", test_serialize_UIntMax),
869+
("test_serialize_UIntMin", test_serialize_UIntMin),
866870
("test_serialize_stringEscaping", test_serialize_stringEscaping),
867871
("test_jsonReadingOffTheEndOfBuffers", test_jsonReadingOffTheEndOfBuffers),
868872
("test_jsonObjectToOutputStreamBuffer", test_jsonObjectToOutputStreamBuffer),
@@ -1054,6 +1058,26 @@ extension TestNSJSONSerialization {
10541058
XCTAssertEqual(try trySerialize(json), "[false,true]")
10551059
}
10561060

1061+
func test_serialize_IntMax() {
1062+
let json: [Any] = [Int.max]
1063+
XCTAssertEqual(try trySerialize(json), "[\(Int.max)]")
1064+
}
1065+
1066+
func test_serialize_IntMin() {
1067+
let json: [Any] = [Int.min]
1068+
XCTAssertEqual(try trySerialize(json), "[\(Int.min)]")
1069+
}
1070+
1071+
func test_serialize_UIntMax() {
1072+
let json: [Any] = [UInt.max]
1073+
XCTAssertEqual(try trySerialize(json), "[\(UInt.max)]")
1074+
}
1075+
1076+
func test_serialize_UIntMin() {
1077+
let json: [Any] = [UInt.min]
1078+
XCTAssertEqual(try trySerialize(json), "[\(UInt.min)]")
1079+
}
1080+
10571081
func test_serialize_stringEscaping() {
10581082
var json = ["foo"]
10591083
XCTAssertEqual(try trySerialize(json), "[\"foo\"]")

0 commit comments

Comments
 (0)