@@ -62,8 +62,9 @@ open class JSONSerialization : NSObject {
62
62
return true
63
63
}
64
64
65
- // object is Swift.String, NSNull, Int, Bool, or UInt
66
- if obj is String || obj is NSNull || obj is Int || obj is Bool || obj is UInt {
65
+ if obj is String || obj is NSNull || obj is Int || obj is Bool || obj is UInt ||
66
+ obj is Int8 || obj is Int16 || obj is Int32 || obj is Int64 ||
67
+ obj is UInt8 || obj is UInt16 || obj is UInt32 || obj is UInt64 {
67
68
return true
68
69
}
69
70
@@ -76,6 +77,10 @@ open class JSONSerialization : NSObject {
76
77
return number. isFinite
77
78
}
78
79
80
+ if let number = obj as? Decimal {
81
+ return number. isFinite
82
+ }
83
+
79
84
// object is Swift.Array
80
85
if let array = obj as? [ Any ? ] {
81
86
for element in array {
@@ -99,8 +104,13 @@ open class JSONSerialization : NSObject {
99
104
// object is NSNumber and is not NaN or infinity
100
105
// For better performance, this (most expensive) test should be last.
101
106
if let number = _SwiftValue. store ( obj) as? NSNumber {
102
- let invalid = number. doubleValue. isInfinite || number. doubleValue. isNaN
103
- return !invalid
107
+ if CFNumberIsFloatType ( number. _cfObject) {
108
+ let dv = number. doubleValue
109
+ let invalid = dv. isInfinite || dv. isNaN
110
+ return !invalid
111
+ } else {
112
+ return true
113
+ }
104
114
}
105
115
106
116
// invalid object
@@ -285,9 +295,7 @@ internal extension JSONSerialization {
285
295
286
296
//MARK: - JSONSerializer
287
297
private struct JSONWriter {
288
-
289
- private let maxUIntLength = String ( describing: UInt . max) . count
290
- private let maxIntLength = String ( describing: Int . max) . count
298
+
291
299
var indent = 0
292
300
let pretty : Bool
293
301
let sortedKeys : Bool
@@ -320,13 +328,37 @@ private struct JSONWriter {
320
328
case let boolValue as Bool :
321
329
serializeBool ( boolValue)
322
330
case let num as Int :
323
- try serializeInt ( value: num)
331
+ serializeInteger ( value: num)
332
+ case let num as Int8 :
333
+ serializeInteger ( value: num)
334
+ case let num as Int16 :
335
+ serializeInteger ( value: num)
336
+ case let num as Int32 :
337
+ serializeInteger ( value: num)
338
+ case let num as Int64 :
339
+ serializeInteger ( value: num)
324
340
case let num as UInt :
325
- try serializeUInt ( value: num)
341
+ serializeInteger ( value: num)
342
+ case let num as UInt8 :
343
+ serializeInteger ( value: num)
344
+ case let num as UInt16 :
345
+ serializeInteger ( value: num)
346
+ case let num as UInt32 :
347
+ serializeInteger ( value: num)
348
+ case let num as UInt64 :
349
+ serializeInteger ( value: num)
326
350
case let array as Array < Any ? > :
327
351
try serializeArray ( array)
328
352
case let dict as Dictionary < AnyHashable , Any ? > :
329
353
try serializeDictionary ( dict)
354
+ case let num as Float :
355
+ try serializeNumber ( NSNumber ( value: num) )
356
+ case let num as Double :
357
+ try serializeNumber ( NSNumber ( value: num) )
358
+ case let num as Decimal :
359
+ writer ( num. description)
360
+ case let num as NSDecimalNumber :
361
+ writer ( num. description)
330
362
case is NSNull :
331
363
try serializeNull ( )
332
364
case _ where _SwiftValue. store ( obj) is NSNumber :
@@ -336,92 +368,33 @@ private struct JSONWriter {
336
368
}
337
369
}
338
370
339
- private func serializeUInt( value: UInt ) throws {
340
- if value == 0 {
341
- writer ( " 0 " )
342
- return
343
- }
344
- var array : [ UInt ] = [ ]
345
- var stringResult = " "
346
- //Maximum length of an UInt
347
- array. reserveCapacity ( maxUIntLength)
348
- stringResult. reserveCapacity ( maxUIntLength)
349
- var number = value
350
-
351
- while number != 0 {
352
- array. append ( number % 10 )
371
+ private func serializeInteger< T: UnsignedInteger > ( value: T , isNegative: Bool = false ) {
372
+ let maxIntLength = 22 // 20 digits in UInt64 + optional sign + trailing '\0'
373
+ let asciiZero : CChar = 0x30 // ASCII '0' == 0x30
374
+ let asciiMinus : CChar = 0x2d // ASCII '-' == 0x2d
375
+
376
+ var number = UInt64 ( value)
377
+ var buffer = Array < CChar > ( repeating: 0 , count: maxIntLength)
378
+ var pos = maxIntLength - 1
379
+
380
+ repeat {
381
+ pos -= 1
382
+ buffer [ pos] = asciiZero + CChar( number % 10 )
353
383
number /= 10
384
+ } while number != 0
385
+
386
+ if isNegative {
387
+ pos -= 1
388
+ buffer [ pos] = asciiMinus
354
389
}
355
-
356
- /*
357
- Step backwards through the array and append the values to the string. This way the values are appended in the correct order.
358
- */
359
- var counter = array. count
360
- while counter > 0 {
361
- counter -= 1
362
- let digit : UInt = array [ counter]
363
- switch digit {
364
- case 0 : stringResult. append ( " 0 " )
365
- case 1 : stringResult. append ( " 1 " )
366
- case 2 : stringResult. append ( " 2 " )
367
- case 3 : stringResult. append ( " 3 " )
368
- case 4 : stringResult. append ( " 4 " )
369
- case 5 : stringResult. append ( " 5 " )
370
- case 6 : stringResult. append ( " 6 " )
371
- case 7 : stringResult. append ( " 7 " )
372
- case 8 : stringResult. append ( " 8 " )
373
- case 9 : stringResult. append ( " 9 " )
374
- default : fatalError ( )
375
- }
376
- }
377
-
378
- writer ( stringResult)
390
+ let output = String ( cString: Array ( buffer. suffix ( from: pos) ) )
391
+ writer ( output)
379
392
}
380
-
381
- private func serializeInt( value: Int ) throws {
382
- if value == 0 {
383
- writer ( " 0 " )
384
- return
385
- }
386
- var array : [ Int ] = [ ]
387
- var stringResult = " "
388
- array. reserveCapacity ( maxIntLength)
389
- //Account for a negative sign
390
- stringResult. reserveCapacity ( maxIntLength + 1 )
391
- var number = value
392
-
393
- while number != 0 {
394
- array. append ( number % 10 )
395
- number /= 10
396
- }
397
- //If negative add minus sign before adding any values
398
- if value < 0 {
399
- stringResult. append ( " - " )
400
- }
401
- /*
402
- Step backwards through the array and append the values to the string. This way the values are appended in the correct order.
403
- */
404
- var counter = array. count
405
- while counter > 0 {
406
- counter -= 1
407
- let digit = array [ counter]
408
- switch digit {
409
- case 0 : stringResult. append ( " 0 " )
410
- case 1 , - 1 : stringResult. append ( " 1 " )
411
- case 2 , - 2 : stringResult. append ( " 2 " )
412
- case 3 , - 3 : stringResult. append ( " 3 " )
413
- case 4 , - 4 : stringResult. append ( " 4 " )
414
- case 5 , - 5 : stringResult. append ( " 5 " )
415
- case 6 , - 6 : stringResult. append ( " 6 " )
416
- case 7 , - 7 : stringResult. append ( " 7 " )
417
- case 8 , - 8 : stringResult. append ( " 8 " )
418
- case 9 , - 9 : stringResult. append ( " 9 " )
419
- default : fatalError ( )
420
- }
421
- }
422
- writer ( stringResult)
393
+
394
+ private func serializeInteger< T: SignedInteger > ( value: T ) {
395
+ serializeInteger ( value: UInt64 ( value. magnitude) , isNegative: value < 0 )
423
396
}
424
-
397
+
425
398
func serializeString( _ str: String ) throws {
426
399
writer ( " \" " )
427
400
for scalar in str. unicodeScalars {
@@ -462,15 +435,30 @@ private struct JSONWriter {
462
435
}
463
436
464
437
mutating func serializeNumber( _ num: NSNumber ) throws {
465
- if num. doubleValue. isInfinite || num. doubleValue. isNaN {
466
- throw NSError ( domain: NSCocoaErrorDomain, code: CocoaError . propertyListReadCorrupt. rawValue, userInfo: [ " NSDebugDescription " : " Number cannot be infinity or NaN " ] )
467
- }
468
-
469
- switch num. _cfTypeID {
470
- case CFBooleanGetTypeID ( ) :
471
- serializeBool ( num. boolValue)
472
- default :
473
- writer ( _serializationString ( for: num) )
438
+ if CFNumberIsFloatType ( num. _cfObject) {
439
+ let dv = num. doubleValue
440
+ if !dv. isFinite {
441
+ let value : String
442
+ if dv. isNaN {
443
+ value = " NaN "
444
+ } else if dv. isInfinite {
445
+ value = " infinite "
446
+ } else {
447
+ value = String ( dv)
448
+ }
449
+
450
+ throw NSError ( domain: NSCocoaErrorDomain, code: CocoaError . propertyListReadCorrupt. rawValue, userInfo: [ " NSDebugDescription " : " Invalid number value ( \( value) ) in JSON write " ] )
451
+ }
452
+
453
+ let string = CFNumberFormatterCreateStringWithNumber ( nil , _numberformatter, num. _cfObject) . _swiftObject
454
+ writer ( string)
455
+ } else {
456
+ switch num. _cfTypeID {
457
+ case CFBooleanGetTypeID ( ) :
458
+ serializeBool ( num. boolValue)
459
+ default :
460
+ writer ( num. stringValue)
461
+ }
474
462
}
475
463
}
476
464
@@ -578,13 +566,6 @@ private struct JSONWriter {
578
566
}
579
567
}
580
568
581
- //[SR-2151] https://bugs.swift.org/browse/SR-2151
582
- private mutating func _serializationString( for number: NSNumber ) -> String {
583
- if !CFNumberIsFloatType( number. _cfObject) {
584
- return number. stringValue
585
- }
586
- return CFNumberFormatterCreateStringWithNumber ( nil , _numberformatter, number. _cfObject) . _swiftObject
587
- }
588
569
}
589
570
590
571
//MARK: - JSONDeserializer
0 commit comments