@@ -377,90 +377,106 @@ extension String {
377
377
locationToScanFrom = buf. location
378
378
return retval
379
379
}
380
-
381
- private func _scan < T: BinaryFloatingPoint > ( buffer buf : inout _NSStringBuffer , locale: Locale ? , neg : Bool , to: ( T ) -> Void , base : UInt ,
382
- numericValue : ( ( _ : unichar ) -> Int ? ) ) -> Bool {
380
+
381
+ internal func scan < T: BinaryFloatingPoint & LosslessStringConvertible > ( _ skipSet : CharacterSet ? , locale: Locale ? , locationToScanFrom : inout Int , to: ( T ) -> Void ) -> Bool {
382
+ var buf = _NSStringBuffer ( string : self , start : locationToScanFrom , end : length )
383
383
let ds = ( locale ?? Locale . current) . decimalSeparator? . first ?? Character ( " . " )
384
- var localResult : T ! = nil
385
- var neg = neg
386
384
387
- while let numeral = numericValue ( buf. currentCharacter) {
388
- localResult = localResult ?? T ( 0 )
389
- // 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"
390
- let limit1 = localResult >= T . greatestFiniteMagnitude / T( base)
391
- let limit2 = localResult > T . greatestFiniteMagnitude / T( base)
392
- let limit3 = T ( numeral - ( neg ? 1 : 0 ) ) >= T . greatestFiniteMagnitude - localResult * T( base)
393
- if ( limit1) && ( limit2 || limit3) {
394
- // apply the clamps and advance past the ending of the buffer where there are still digits
395
- localResult = neg ? - T. infinity : T . infinity
396
- neg = false
397
- repeat {
398
- buf. advance ( )
399
- } while numericValue ( buf. currentCharacter) != nil
400
- break
401
- } else {
402
- localResult = localResult * T( base) + T( numeral)
385
+ func nextDigit( ) -> Character ? {
386
+ if let s = UnicodeScalar ( buf. currentCharacter) {
387
+ let ch = Character ( s)
388
+ if ch. isASCII && ch. isWholeNumber {
389
+ return ch
390
+ }
403
391
}
392
+ return nil
393
+ }
394
+
395
+ var hasValidCharacter = false
396
+ var stringToParse = checkForNegative ( inBuffer: & buf, skipping: skipSet) ? " - " : " "
397
+
398
+ while let ch = nextDigit ( ) {
399
+ hasValidCharacter = true
400
+ stringToParse. append ( ch)
404
401
buf. advance ( )
405
402
}
406
-
407
403
if let us = UnicodeScalar ( buf. currentCharacter) , Character ( us) == ds {
408
- var factor = 1 / T ( base )
404
+ stringToParse += " . "
409
405
buf. advance ( )
410
- while let numeral = numericValue ( buf. currentCharacter) {
411
- localResult = localResult ?? T ( 0 )
412
- localResult = localResult + T( numeral) * factor
413
- factor = factor / T( base)
406
+ while let ch = nextDigit ( ) {
407
+ hasValidCharacter = true
408
+ stringToParse. append ( ch)
414
409
buf. advance ( )
415
410
}
416
411
}
412
+ guard hasValidCharacter else { return false }
417
413
418
- guard localResult != nil else {
419
- return false
420
- }
421
-
422
- // 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.
423
414
if buf. currentCharacter == unichar ( unicodeScalarLiteral: " e " ) || buf. currentCharacter == unichar ( unicodeScalarLiteral: " E " ) {
424
- var exponent = Double ( 0 )
425
-
415
+ hasValidCharacter = false
416
+ stringToParse += " e "
426
417
buf. advance ( )
427
- let negExponent = checkForNegative ( inBuffer: & buf)
428
-
429
- while let numeral = numericValue ( buf. currentCharacter) {
430
- buf. advance ( )
431
- exponent *= Double ( base)
432
- exponent += Double ( numeral)
418
+ if checkForNegative ( inBuffer: & buf) {
419
+ stringToParse += " - "
433
420
}
434
-
435
- if exponent > 0 {
436
- let multiplier = pow ( Double ( base) , exponent)
437
- if negExponent {
438
- localResult /= T ( multiplier)
439
- } else {
440
- localResult *= T ( multiplier)
441
- }
421
+ while let ch = nextDigit ( ) {
422
+ hasValidCharacter = true
423
+ stringToParse. append ( ch)
424
+ buf. advance ( )
442
425
}
443
426
}
427
+ guard hasValidCharacter else { return false }
444
428
445
- to ( neg ? T ( - 1 ) * localResult : localResult)
446
- return true
429
+ if let value = T ( stringToParse) {
430
+ to ( value)
431
+ locationToScanFrom = buf. location
432
+ return true
433
+ } else {
434
+ return false
435
+ }
447
436
}
448
437
449
- internal func scan < T: BinaryFloatingPoint > ( _ skipSet: CharacterSet ? , locale: Locale ? , locationToScanFrom: inout Int , to: ( T ) -> Void ) -> Bool {
438
+ internal func scanHex < T: BinaryFloatingPoint & LosslessStringConvertible > ( _ skipSet: CharacterSet ? , locale: Locale ? , locationToScanFrom: inout Int , to: ( T ) -> Void ) -> Bool {
450
439
var buf = _NSStringBuffer ( string: self , start: locationToScanFrom, end: length)
451
- let neg = checkForNegative ( inBuffer: & buf, skipping: skipSet)
452
- let result = _scan ( buffer: & buf, locale: locale, neg: neg, to: to, base: 10 , numericValue: decimalValue)
453
- locationToScanFrom = buf. location
454
- return result
455
- }
440
+ let ds = ( locale ?? Locale . current) . decimalSeparator? . first ?? Character ( " . " )
456
441
457
- internal func scanHex< T: BinaryFloatingPoint > ( _ skipSet: CharacterSet ? , locale: Locale ? , locationToScanFrom: inout Int , to: ( T ) -> Void ) -> Bool {
458
- var buf = _NSStringBuffer ( string: self , start: locationToScanFrom, end: length)
459
- let neg = checkForNegative ( inBuffer: & buf, skipping: skipSet)
442
+ func nextHexDigit( ) -> Character ? {
443
+ if let s = UnicodeScalar ( buf. currentCharacter) , let ascii = Character ( s) . asciiValue {
444
+ switch ascii {
445
+ case 0x30 ... 0x39 , 0x41 ... 0x46 , 0x61 ... 0x66 : return Character ( s)
446
+ default : return nil
447
+ }
448
+ } else {
449
+ return nil
450
+ }
451
+ }
452
+
453
+ var hasValidCharacter = false
454
+ var stringToParse = checkForNegative ( inBuffer: & buf, skipping: skipSet) ? " -0x " : " 0x "
460
455
skipHexStart ( inBuffer: & buf)
461
- let result = _scan ( buffer: & buf, locale: locale, neg: neg, to: to, base: 16 , numericValue: decimalOrHexValue)
462
- locationToScanFrom = buf. location
463
- return result
456
+
457
+ while let ch = nextHexDigit ( ) {
458
+ hasValidCharacter = true
459
+ stringToParse. append ( ch)
460
+ buf. advance ( )
461
+ }
462
+ if let us = UnicodeScalar ( buf. currentCharacter) , Character ( us) == ds {
463
+ stringToParse += " . "
464
+ buf. advance ( )
465
+ while let ch = nextHexDigit ( ) {
466
+ hasValidCharacter = true
467
+ stringToParse. append ( ch)
468
+ buf. advance ( )
469
+ }
470
+ }
471
+ guard hasValidCharacter else { return false }
472
+
473
+ if let value = T ( stringToParse) {
474
+ to ( value)
475
+ locationToScanFrom = buf. location
476
+ return true
477
+ } else {
478
+ return false
479
+ }
464
480
}
465
481
}
466
482
0 commit comments