7
7
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
8
8
//
9
9
10
- import CoreFoundation
11
10
12
11
open class Scanner : NSObject , NSCopying {
13
12
internal var _scanString : String
@@ -286,199 +285,145 @@ internal struct _NSStringBuffer {
286
285
}
287
286
}
288
287
289
- private func isADigit( _ ch: unichar ) -> Bool {
290
- struct Local {
291
- static let set = CharacterSet . decimalDigits
292
- }
293
- return Local . set. contains ( UnicodeScalar ( ch) !)
294
- }
295
-
296
288
297
- private func numericValue( _ ch: unichar ) -> Int {
298
- if ( ch >= unichar ( unicodeScalarLiteral: " 0 " ) && ch <= unichar ( unicodeScalarLiteral: " 9 " ) ) {
299
- return Int ( ch) - Int( unichar ( unicodeScalarLiteral: " 0 " ) )
300
- } else {
301
- return __CFCharDigitValue ( UniChar ( ch) )
302
- }
289
+ private func decimalValue( _ ch: unichar ) -> Int ? {
290
+ guard let s = UnicodeScalar ( ch) , s. isASCII else { return nil }
291
+ return Character ( s) . wholeNumberValue
303
292
}
304
293
305
- private func numericOrHexValue( _ ch: unichar ) -> Int {
306
- if ( ch >= unichar ( unicodeScalarLiteral: " 0 " ) && ch <= unichar ( unicodeScalarLiteral: " 9 " ) ) {
307
- return Int ( ch) - Int( unichar ( unicodeScalarLiteral: " 0 " ) )
308
- } else if ( ch >= unichar ( unicodeScalarLiteral: " A " ) && ch <= unichar ( unicodeScalarLiteral: " F " ) ) {
309
- return Int ( ch) + 10 - Int( unichar ( unicodeScalarLiteral: " A " ) )
310
- } else if ( ch >= unichar ( unicodeScalarLiteral: " a " ) && ch <= unichar ( unicodeScalarLiteral: " f " ) ) {
311
- return Int ( ch) + 10 - Int( unichar ( unicodeScalarLiteral: " a " ) )
312
- } else {
313
- return - 1
314
- }
294
+ private func decimalOrHexValue( _ ch: unichar ) -> Int ? {
295
+ guard let s = UnicodeScalar ( ch) , s. isASCII else { return nil }
296
+ return Character ( s) . hexDigitValue
315
297
}
316
298
317
- private func decimalSep( _ locale: Locale ? ) -> String {
318
- if let loc = locale {
319
- if let sep = loc. _bridgeToObjectiveC ( ) . object ( forKey: . decimalSeparator) as? NSString {
320
- return sep. _swiftObject
321
- }
322
- return " . "
323
- } else {
324
- return decimalSep ( Locale . current)
325
- }
326
- }
327
299
328
300
extension String {
329
- internal func scan < T : FixedWidthInteger > ( _ skipSet : CharacterSet ? , locationToScanFrom : inout Int , to : ( T ) -> Void ) -> Bool {
330
- var buf = _NSStringBuffer ( string : self , start : locationToScanFrom , end : length )
301
+
302
+ private func checkForNegative ( inBuffer buf: inout _NSStringBuffer , skipping skipSet : CharacterSet ? = nil ) -> Bool {
331
303
buf. skip ( skipSet)
332
- var neg = false
333
- var localResult : T = 0
334
304
if buf. currentCharacter == unichar ( unicodeScalarLiteral: " - " ) || buf. currentCharacter == unichar ( unicodeScalarLiteral: " + " ) {
335
- neg = buf. currentCharacter == unichar ( unicodeScalarLiteral: " - " )
305
+ let neg = buf. currentCharacter == unichar ( unicodeScalarLiteral: " - " )
336
306
buf. advance ( )
337
307
buf. skip ( skipSet)
308
+ return neg
338
309
}
339
- if ( !isADigit( buf. currentCharacter) ) {
340
- return false
341
- }
342
- repeat {
343
- let numeral = numericValue ( buf. currentCharacter)
344
- if numeral == - 1 {
345
- break
310
+ return false
311
+ }
312
+
313
+ // If a string starts: 0[xX]<Valid Hex Digits> return with the buffer pointing to the hex digits otherwise point to the start of buffer.
314
+ private func skipHexStart( inBuffer buf: inout _NSStringBuffer ) {
315
+ let locRewindTo = buf. location
316
+ if buf. currentCharacter == unichar ( unicodeScalarLiteral: " 0 " ) {
317
+ buf. advance ( )
318
+ if buf. currentCharacter == unichar ( unicodeScalarLiteral: " x " ) || buf. currentCharacter == unichar ( unicodeScalarLiteral: " X " ) {
319
+ buf. advance ( )
320
+ if decimalOrHexValue ( buf. currentCharacter) != nil {
321
+ return
322
+ }
346
323
}
324
+ buf. location = locRewindTo
325
+ }
326
+ }
327
+
328
+ internal func scan< T: FixedWidthInteger > ( _ skipSet: CharacterSet ? , locationToScanFrom: inout Int , to: ( T ) -> Void ) -> Bool {
329
+ var buf = _NSStringBuffer ( string: self , start: locationToScanFrom, end: length)
330
+ var localResult : T = 0
331
+ var retval = false
332
+ var neg = checkForNegative ( inBuffer: & buf, skipping: skipSet)
333
+
334
+ while let numeral = decimalValue ( buf. currentCharacter) {
335
+ retval = true
347
336
if ( localResult >= T . max / 10 ) && ( ( localResult > T . max / 10 ) || T ( numeral - ( neg ? 1 : 0 ) ) >= T . max - localResult * 10 ) {
348
337
// apply the clamps and advance past the ending of the buffer where there are still digits
349
338
localResult = neg ? T . min : T . max
350
339
neg = false
351
340
repeat {
352
341
buf. advance ( )
353
- } while ( isADigit ( buf. currentCharacter) )
342
+ } while decimalValue ( buf. currentCharacter) != nil
354
343
break
355
344
} else {
356
345
// normal case for scanning
357
346
localResult = localResult * 10 + T( numeral)
358
347
}
359
348
buf. advance ( )
360
- } while ( isADigit ( buf . currentCharacter ) )
349
+ }
361
350
to ( neg ? - 1 * localResult : localResult)
362
351
locationToScanFrom = buf. location
363
- return true
352
+ return retval
364
353
}
365
-
354
+
366
355
internal func scanHex< T: FixedWidthInteger > ( _ skipSet: CharacterSet ? , locationToScanFrom: inout Int , to: ( T ) -> Void ) -> Bool {
367
356
var buf = _NSStringBuffer ( string: self , start: locationToScanFrom, end: length)
368
- buf. skip ( skipSet)
369
357
var localResult : T = 0
370
- var curDigit : Int
371
- if buf. currentCharacter == unichar ( unicodeScalarLiteral: " 0 " ) {
372
- buf. advance ( )
373
- let locRewindTo = buf. location
374
- curDigit = numericOrHexValue ( buf. currentCharacter)
375
- if curDigit == - 1 {
376
- if buf. currentCharacter == unichar ( unicodeScalarLiteral: " x " ) || buf. currentCharacter == unichar ( unicodeScalarLiteral: " X " ) {
377
- buf. advance ( )
378
- curDigit = numericOrHexValue ( buf. currentCharacter)
379
- }
380
- }
381
- if curDigit == - 1 {
382
- locationToScanFrom = locRewindTo
383
- to ( T ( 0 ) )
384
- return true
385
- }
386
- } else {
387
- curDigit = numericOrHexValue ( buf. currentCharacter)
388
- if curDigit == - 1 {
389
- return false
390
- }
391
- }
392
-
393
- repeat {
358
+ var retval = false
359
+ buf. skip ( skipSet)
360
+ skipHexStart ( inBuffer: & buf)
361
+
362
+ while let numeral = decimalOrHexValue ( buf. currentCharacter) {
363
+ retval = true
394
364
if localResult > T . max >> T ( 4 ) {
395
365
localResult = T . max
396
366
} else {
397
- localResult = ( localResult << T ( 4 ) ) + T( curDigit )
367
+ localResult = ( localResult << T ( 4 ) ) + T( numeral )
398
368
}
399
369
buf. advance ( )
400
- curDigit = numericOrHexValue ( buf. currentCharacter)
401
- } while ( curDigit != - 1 )
402
-
370
+ }
371
+
403
372
to ( localResult)
404
373
locationToScanFrom = buf. location
405
- return true
374
+ return retval
406
375
}
407
376
408
- internal func scan< T: BinaryFloatingPoint > ( _ skipSet: CharacterSet ? , locale: Locale ? , locationToScanFrom: inout Int , to: ( T ) -> Void ) -> Bool {
409
- let ds_chars = decimalSep ( locale) . utf16
410
- let ds = ds_chars [ ds_chars. startIndex]
411
- var buf = _NSStringBuffer ( string: self , start: locationToScanFrom, end: length)
412
- buf. skip ( skipSet)
413
- var neg = false
377
+ private func _scan< T: BinaryFloatingPoint > ( buffer buf: inout _NSStringBuffer , locale: Locale ? , neg: Bool , to: ( T ) -> Void , base: UInt ,
378
+ numericValue: ( ( _: unichar ) -> Int ? ) ) -> Bool {
379
+ let ds = ( locale ?? Locale . current) . decimalSeparator? . first ?? Character ( " . " )
414
380
var localResult : T = T ( 0 )
415
-
416
- if buf. currentCharacter == unichar ( unicodeScalarLiteral: " - " ) || buf. currentCharacter == unichar ( unicodeScalarLiteral: " + " ) {
417
- neg = buf. currentCharacter == unichar ( unicodeScalarLiteral: " - " )
418
- buf. advance ( )
419
- buf. skip ( skipSet)
420
- }
421
- if ( buf. currentCharacter != ds && !isADigit( buf. currentCharacter) ) {
422
- return false
423
- }
424
-
425
- repeat {
426
- let numeral = numericValue ( buf. currentCharacter)
427
- if numeral == - 1 {
428
- break
429
- }
381
+ var neg = neg
382
+
383
+ while let numeral = numericValue ( buf. currentCharacter) {
430
384
// if (localResult >= T.greatestFiniteMagnitude / T(10)) && ((localResult > T.greatestFiniteMagnitude / T(10)) || T(numericValue(buf.currentCharacter) - (neg ? 1 : 0)) >= T.greatestFiniteMagnitude - localResult * T(10)) is evidently too complex; so break it down to more "edible chunks"
431
- let limit1 = localResult >= T . greatestFiniteMagnitude / T( 10 )
432
- let limit2 = localResult > T . greatestFiniteMagnitude / T( 10 )
433
- let limit3 = T ( numeral - ( neg ? 1 : 0 ) ) >= T . greatestFiniteMagnitude - localResult * T( 10 )
385
+ let limit1 = localResult >= T . greatestFiniteMagnitude / T( base )
386
+ let limit2 = localResult > T . greatestFiniteMagnitude / T( base )
387
+ let limit3 = T ( numeral - ( neg ? 1 : 0 ) ) >= T . greatestFiniteMagnitude - localResult * T( base )
434
388
if ( limit1) && ( limit2 || limit3) {
435
389
// apply the clamps and advance past the ending of the buffer where there are still digits
436
390
localResult = neg ? - T. infinity : T . infinity
437
391
neg = false
438
392
repeat {
439
393
buf. advance ( )
440
- } while ( isADigit ( buf. currentCharacter) )
394
+ } while numericValue ( buf. currentCharacter) != nil
441
395
break
442
396
} else {
443
- localResult = localResult * T( 10 ) + T( numeral)
397
+ localResult = localResult * T( base ) + T( numeral)
444
398
}
445
399
buf. advance ( )
446
- } while ( isADigit ( buf . currentCharacter ) )
400
+ }
447
401
448
- if buf. currentCharacter == ds {
449
- var factor = T ( 0.1 )
402
+ if let us = UnicodeScalar ( buf. currentCharacter) , Character ( us ) == ds {
403
+ var factor = 1 / T ( base )
450
404
buf. advance ( )
451
- repeat {
452
- let numeral = numericValue ( buf. currentCharacter)
453
- if numeral == - 1 {
454
- break
455
- }
405
+ while let numeral = numericValue ( buf. currentCharacter) {
456
406
localResult = localResult + T( numeral) * factor
457
- factor = factor * T( 0.1 )
407
+ factor = factor / T( base )
458
408
buf. advance ( )
459
- } while ( isADigit ( buf . currentCharacter ) )
409
+ }
460
410
}
461
411
412
+ // If this is used to parse a number in Hexadecimal, this will never be true as the 'e' or 'E' will be caught by the previous loop.
462
413
if buf. currentCharacter == unichar ( unicodeScalarLiteral: " e " ) || buf. currentCharacter == unichar ( unicodeScalarLiteral: " E " ) {
463
414
var exponent = Double ( 0 )
464
- var negExponent = false
415
+
465
416
buf. advance ( )
466
- if buf. currentCharacter == unichar ( unicodeScalarLiteral: " - " ) || buf. currentCharacter == unichar ( unicodeScalarLiteral: " + " ) {
467
- negExponent = buf. currentCharacter == unichar ( unicodeScalarLiteral: " - " )
468
- buf. advance ( )
469
- }
470
- repeat {
471
- let numeral = numericValue ( buf. currentCharacter)
417
+ let negExponent = checkForNegative ( inBuffer: & buf)
418
+
419
+ while let numeral = numericValue ( buf. currentCharacter) {
472
420
buf. advance ( )
473
- if numeral == - 1 {
474
- break
475
- }
476
- exponent *= 10
421
+ exponent *= Double ( base)
477
422
exponent += Double ( numeral)
478
- } while ( isADigit ( buf . currentCharacter ) )
423
+ }
479
424
480
425
if exponent > 0 {
481
- let multiplier = pow ( 10 , exponent)
426
+ let multiplier = pow ( Double ( base ) , exponent)
482
427
if negExponent {
483
428
localResult /= T ( multiplier)
484
429
} else {
@@ -488,12 +433,24 @@ extension String {
488
433
}
489
434
490
435
to ( neg ? T ( - 1 ) * localResult : localResult)
491
- locationToScanFrom = buf. location
492
436
return true
493
437
}
494
-
438
+
439
+ internal func scan< T: BinaryFloatingPoint > ( _ skipSet: CharacterSet ? , locale: Locale ? , locationToScanFrom: inout Int , to: ( T ) -> Void ) -> Bool {
440
+ var buf = _NSStringBuffer ( string: self , start: locationToScanFrom, end: length)
441
+ let neg = checkForNegative ( inBuffer: & buf, skipping: skipSet)
442
+ let result = _scan ( buffer: & buf, locale: locale, neg: neg, to: to, base: 10 , numericValue: decimalValue)
443
+ locationToScanFrom = buf. location
444
+ return result
445
+ }
446
+
495
447
internal func scanHex< T: BinaryFloatingPoint > ( _ skipSet: CharacterSet ? , locale: Locale ? , locationToScanFrom: inout Int , to: ( T ) -> Void ) -> Bool {
496
- NSUnimplemented ( )
448
+ var buf = _NSStringBuffer ( string: self , start: locationToScanFrom, end: length)
449
+ let neg = checkForNegative ( inBuffer: & buf, skipping: skipSet)
450
+ skipHexStart ( inBuffer: & buf)
451
+ let result = _scan ( buffer: & buf, locale: locale, neg: neg, to: to, base: 16 , numericValue: decimalOrHexValue)
452
+ locationToScanFrom = buf. location
453
+ return result
497
454
}
498
455
}
499
456
0 commit comments