Skip to content

Commit 97b4581

Browse files
authored
Improve performance of JSONDecoder and JSONEncoder for large apps (#1481)
* Improve performance of JSONDecoder and JSONEncoder for large apps * use switch instead of casting to protocol * replace as with specializingCast * fix styling and remove extra diff * make extensions fileprivate
1 parent 57b6c0c commit 97b4581

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

Sources/FoundationEssentials/JSON/JSONDecoder.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ extension JSONDecoderImpl: Decoder {
610610
if type == Decimal.self {
611611
return try self.unwrapDecimal(from: mapValue, for: codingPathNode, additionalKey) as! T
612612
}
613-
if T.self is _JSONStringDictionaryDecodableMarker.Type {
613+
if !options.keyDecodingStrategy.isDefault, T.self is _JSONStringDictionaryDecodableMarker.Type {
614614
return try self.unwrapDictionary(from: mapValue, as: type, for: codingPathNode, additionalKey)
615615
}
616616

@@ -1857,5 +1857,14 @@ extension EncodingError {
18571857
}
18581858
}
18591859

1860+
fileprivate extension JSONDecoder.KeyDecodingStrategy {
1861+
var isDefault: Bool {
1862+
switch self {
1863+
case .useDefaultKeys: true
1864+
default: false
1865+
}
1866+
}
1867+
}
1868+
18601869
@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)
18611870
extension JSONDecoder : @unchecked Sendable {}

Sources/FoundationEssentials/JSON/JSONEncoder.swift

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,9 +1214,9 @@ private extension __JSONEncoder {
12141214
return self.wrap(url.absoluteString)
12151215
} else if let decimal = value as? Decimal {
12161216
return .number(decimal.description)
1217-
} else if let encodable = value as? _JSONStringDictionaryEncodableMarker {
1217+
} else if !options.keyEncodingStrategy.isDefault, let encodable = value as? _JSONStringDictionaryEncodableMarker {
12181218
return try self.wrap(encodable as! [String:Encodable], for: additionalKey)
1219-
} else if let array = value as? _JSONDirectArrayEncodable {
1219+
} else if let array = _asDirectArrayEncodable(value, for: additionalKey) {
12201220
if options.outputFormatting.contains(.prettyPrinted) {
12211221
let (bytes, lengths) = try array.individualElementRepresentation(encoder: self, additionalKey)
12221222
return .directArray(bytes, lengths: lengths)
@@ -1246,6 +1246,42 @@ private extension __JSONEncoder {
12461246
return encoder.takeValue()
12471247
}
12481248

1249+
func _asDirectArrayEncodable<T: Encodable>(_ value: T, for additionalKey: (some CodingKey)? = _CodingKey?.none) -> _JSONDirectArrayEncodable? {
1250+
return if let array = _specializingCast(array, to: [Int8].self) {
1251+
array
1252+
} else if let array = _specializingCast(array, to: [Int16].self) {
1253+
array
1254+
} else if let array = _specializingCast(array, to: [Int32].self) {
1255+
array
1256+
} else if let array = _specializingCast(array, to: [Int64].self) {
1257+
array
1258+
} else if let array = _specializingCast(array, to: [Int128].self) {
1259+
array
1260+
} else if let array = _specializingCast(array, to: [Int].self) {
1261+
array
1262+
} else if let array = _specializingCast(array, to: [UInt8].self) {
1263+
array
1264+
} else if let array = _specializingCast(array, to: [UInt16].self) {
1265+
array
1266+
} else if let array = _specializingCast(array, to: [UInt32].self) {
1267+
array
1268+
} else if let array = _specializingCast(array, to: [UInt64].self) {
1269+
array
1270+
} else if let array = _specializingCast(array, to: [UInt128].self) {
1271+
array
1272+
} else if let array = _specializingCast(array, to: [UInt].self) {
1273+
array
1274+
} else if let array = _specializingCast(array, to: [String].self) {
1275+
array
1276+
} else if let array = _specializingCast(array, to: [Float].self) {
1277+
array
1278+
} else if let array = _specializingCast(array, to: [Double].self) {
1279+
array
1280+
} else {
1281+
nil
1282+
}
1283+
}
1284+
12491285
@inline(__always)
12501286
func getEncoder(for additionalKey: CodingKey?) -> __JSONEncoder {
12511287
if let additionalKey {
@@ -1466,3 +1502,14 @@ extension Array : _JSONDirectArrayEncodable where Element: _JSONSimpleValueArray
14661502
return (writer.bytes, lengths: byteLengths)
14671503
}
14681504
}
1505+
1506+
fileprivate extension JSONEncoder.KeyEncodingStrategy {
1507+
var isDefault: Bool {
1508+
switch self {
1509+
case .useDefaultKeys:
1510+
return true
1511+
case .custom, .convertToSnakeCase:
1512+
return false
1513+
}
1514+
}
1515+
}

0 commit comments

Comments
 (0)