Skip to content

Commit 409a9e9

Browse files
authored
Merge pull request #1724 from spevans/pr_sr_1464
2 parents 1f06596 + 7cb608f commit 409a9e9

File tree

6 files changed

+197
-44
lines changed

6 files changed

+197
-44
lines changed

CoreFoundation/String.subproj/CFString.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6013,7 +6013,7 @@ enum {
60136013
CFFormatDummyPointerType = 42 /* special case for %n */
60146014
};
60156015

6016-
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
6016+
#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX
60176017
/* Only come in here if spec->type is CFFormatLongType or CFFormatDoubleType. Pass in 0 for width or precision if not specified. Returns false if couldn't do the format (with the assumption the caller falls back to unlocalized).
60186018
*/
60196019
static Boolean __CFStringFormatLocalizedNumber(CFMutableStringRef output, CFLocaleRef locale, const CFPrintValue *values, const CFFormatSpec *spec, SInt32 width, SInt32 precision, Boolean hasPrecision) {
@@ -7109,7 +7109,7 @@ static Boolean __CFStringAppendFormatCore(CFMutableStringRef outputString, CFStr
71097109
switch (specs[curSpec].type) {
71107110
case CFFormatLongType:
71117111
case CFFormatDoubleType:
7112-
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
7112+
#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX
71137113
if (localizedFormatting && (specs[curSpec].flags & kCFStringFormatLocalizable)) { // We have a locale, so we do localized formatting
71147114
if (__CFStringFormatLocalizedNumber(outputString, (CFLocaleRef)formatOptions, values, &specs[curSpec], width, precision, hasPrecision)) break;
71157115
}

Foundation/NSDecimalNumber.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,11 @@ open class NSDecimalNumber : NSNumber {
212212
public required convenience init(bytes buffer: UnsafeRawPointer, objCType type: UnsafePointer<Int8>) {
213213
NSRequiresConcreteImplementation()
214214
}
215-
215+
216+
open override var description: String {
217+
return self.decimal.description
218+
}
219+
216220
open override func description(withLocale locale: Locale?) -> String {
217221
guard locale == nil else {
218222
fatalError("Locale not supported: \(locale!)")

Foundation/NSNumber.swift

Lines changed: 70 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ open class NSNumber : NSValue {
919919
}
920920

921921
open var stringValue: String {
922-
return description(withLocale: nil)
922+
return self.description
923923
}
924924

925925
/// Create an instance initialized to `value`.
@@ -962,39 +962,86 @@ open class NSNumber : NSValue {
962962
}
963963
}
964964

965-
private static let _numberFormatterForNilLocale: CFNumberFormatter = {
966-
let formatter: CFNumberFormatter
967-
formatter = CFNumberFormatterCreate(nil, CFLocaleCopyCurrent(), kCFNumberFormatterNoStyle)
968-
CFNumberFormatterSetProperty(formatter, kCFNumberFormatterMaxFractionDigits, 15._bridgeToObjectiveC())
969-
return formatter
970-
}()
971-
972965
open func description(withLocale locale: Locale?) -> String {
973-
// CFNumberFormatterCreateStringWithNumber() does not like numbers of type
974-
// SInt128Type, as it loses the type when looking it up and treats it as
975-
// an SInt64Type, so special case them.
976-
if _CFNumberGetType2(_cfObject) == kCFNumberSInt128Type {
977-
return String(format: "%@", unsafeBitCast(_cfObject, to: UnsafePointer<CFNumber>.self))
978-
}
966+
guard let locale = locale else { return self.description }
967+
switch _CFNumberGetType2(_cfObject) {
968+
case kCFNumberSInt8Type, kCFNumberCharType:
969+
return String(format: "%d", locale: locale, self.int8Value)
979970

980-
let aLocale = locale
981-
let formatter: CFNumberFormatter
982-
if (aLocale == nil) {
983-
formatter = NSNumber._numberFormatterForNilLocale
984-
} else {
985-
formatter = CFNumberFormatterCreate(nil, aLocale?._cfObject, kCFNumberFormatterDecimalStyle)
971+
case kCFNumberSInt16Type, kCFNumberShortType:
972+
return String(format: "%hi", locale: locale, self.int16Value)
973+
974+
case kCFNumberSInt32Type:
975+
return String(format: "%d", locale: locale, self.int32Value)
976+
977+
case kCFNumberIntType, kCFNumberLongType, kCFNumberNSIntegerType, kCFNumberCFIndexType:
978+
return String(format: "%ld", locale: locale, self.intValue)
979+
980+
case kCFNumberSInt64Type, kCFNumberLongLongType:
981+
return String(format: "%lld", locale: locale, self.int64Value)
982+
983+
case kCFNumberSInt128Type:
984+
let value = self.int128Value
985+
if value.high == 0 {
986+
return value.low.description // BUG: "%llu" doesnt work correctly and treats number as signed
987+
} else {
988+
// BUG: Note the locale is actually ignored here as this is converted using CFNumber.c:emit128()
989+
return String(format: "%@", locale: locale, unsafeBitCast(_cfObject, to: UnsafePointer<CFNumber>.self))
990+
}
991+
992+
case kCFNumberFloatType, kCFNumberCGFloatType, kCFNumberFloatType:
993+
return String(format: "%0.7g", locale: locale, self.floatValue)
994+
995+
case kCFNumberFloat64Type, kCFNumberDoubleType:
996+
return String(format: "%0.16g", locale: locale, self.doubleValue)
997+
998+
case kCFNumberCGFloatType:
999+
if Int.max == Int32.max {
1000+
return String(format: "%0.7g", locale: locale, self.floatValue)
1001+
} else {
1002+
return String(format: "%0.16g", locale: locale, self.doubleValue)
1003+
}
1004+
default: fatalError("Unknown NSNumber Type")
9861005
}
987-
return CFNumberFormatterCreateStringWithNumber(nil, formatter, self._cfObject)._swiftObject
9881006
}
9891007

9901008
override open var _cfTypeID: CFTypeID {
9911009
return CFNumberGetTypeID()
9921010
}
9931011

9941012
open override var description: String {
995-
return description(withLocale: nil)
1013+
switch _CFNumberGetType2(_cfObject) {
1014+
case kCFNumberSInt8Type, kCFNumberCharType, kCFNumberSInt16Type, kCFNumberShortType,
1015+
kCFNumberSInt32Type, kCFNumberIntType, kCFNumberLongType, kCFNumberNSIntegerType, kCFNumberCFIndexType:
1016+
return self.intValue.description
1017+
1018+
case kCFNumberSInt64Type, kCFNumberLongLongType:
1019+
return self.int64Value.description
1020+
1021+
case kCFNumberSInt128Type:
1022+
let value = self.int128Value
1023+
if value.high == 0 {
1024+
return value.low.description
1025+
} else {
1026+
return String(format: "%@", locale: nil, unsafeBitCast(_cfObject, to: UnsafePointer<CFNumber>.self))
1027+
}
1028+
1029+
case kCFNumberFloatType, kCFNumberCGFloatType, kCFNumberFloatType:
1030+
return self.floatValue.description
1031+
1032+
case kCFNumberFloat64Type, kCFNumberDoubleType:
1033+
return self.doubleValue.description
1034+
1035+
case kCFNumberCGFloatType:
1036+
if Int.max == Int32.max {
1037+
return self.floatValue.description
1038+
} else {
1039+
return self.doubleValue.description
1040+
}
1041+
default: fatalError("Unknown NSNumber Type")
1042+
}
9961043
}
997-
1044+
9981045
internal func _cfNumberType() -> CFNumberType {
9991046
switch objCType.pointee {
10001047
case 0x42: return kCFNumberCharType

TestFoundation/TestDecimal.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ class TestDecimal: XCTestCase {
518518
XCTAssertEqual(1, ten._length)
519519
}
520520

521-
func test_NSDecimal() {
521+
func test_NSDecimal() throws {
522522
var nan = Decimal.nan
523523
XCTAssertTrue(NSDecimalIsNotANumber(&nan))
524524
var zero = Decimal()
@@ -539,6 +539,31 @@ class TestDecimal: XCTestCase {
539539
let nsd1 = NSDecimalNumber(decimal: Decimal(2657.6))
540540
let nsd2 = NSDecimalNumber(floatLiteral: 2657.6)
541541
XCTAssertEqual(nsd1, nsd2)
542+
543+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(Int8.min)).description, Int8.min.description)
544+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(Int8.max)).description, Int8.max.description)
545+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(UInt8.min)).description, UInt8.min.description)
546+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(UInt8.max)).description, UInt8.max.description)
547+
548+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(Int16.min)).description, Int16.min.description)
549+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(Int16.max)).description, Int16.max.description)
550+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(UInt16.min)).description, UInt16.min.description)
551+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(UInt16.max)).description, UInt16.max.description)
552+
553+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(Int32.min)).description, Int32.min.description)
554+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(Int32.max)).description, Int32.max.description)
555+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(UInt32.min)).description, UInt32.min.description)
556+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(UInt32.max)).description, UInt32.max.description)
557+
558+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(Int64.min)).description, Int64.min.description)
559+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(Int64.max)).description, Int64.max.description)
560+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(UInt64.min)).description, UInt64.min.description)
561+
XCTAssertEqual(NSDecimalNumber(decimal: Decimal(UInt64.max)).description, UInt64.max.description)
562+
563+
XCTAssertEqual(try NSDecimalNumber(decimal: Decimal(string: "12.34").unwrapped()).description, "12.34")
564+
XCTAssertEqual(try NSDecimalNumber(decimal: Decimal(string: "0.0001").unwrapped()).description, "0.0001")
565+
XCTAssertEqual(try NSDecimalNumber(decimal: Decimal(string: "-1.0002").unwrapped()).description, "-1.0002")
566+
XCTAssertEqual(try NSDecimalNumber(decimal: Decimal(string: "0.0").unwrapped()).description, "0")
542567
}
543568

544569
func test_PositivePowers() {

TestFoundation/TestNSNumber.swift

Lines changed: 92 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,21 +1016,100 @@ class TestNSNumber : XCTestCase {
10161016

10171017

10181018
func test_description() {
1019-
let nsnumber: NSNumber = 1000
1020-
let expectedDesc = "1000"
1021-
XCTAssertEqual(nsnumber.description, expectedDesc, "expected \(expectedDesc) but received \(nsnumber.description)")
1019+
XCTAssertEqual(NSNumber(value: 1000).description, "1000")
1020+
XCTAssertEqual(NSNumber(value: 0.001).description, "0.001")
1021+
1022+
XCTAssertEqual(NSNumber(value: Int8.min).description, "-128")
1023+
XCTAssertEqual(NSNumber(value: Int8.max).description, "127")
1024+
XCTAssertEqual(NSNumber(value: Int16.min).description, "-32768")
1025+
XCTAssertEqual(NSNumber(value: Int16.max).description, "32767")
1026+
XCTAssertEqual(NSNumber(value: Int32.min).description, "-2147483648")
1027+
XCTAssertEqual(NSNumber(value: Int32.max).description, "2147483647")
1028+
XCTAssertEqual(NSNumber(value: Int64.min).description, "-9223372036854775808")
1029+
XCTAssertEqual(NSNumber(value: Int64.max).description, "9223372036854775807")
1030+
1031+
XCTAssertEqual(NSNumber(value: UInt8.min).description, "0")
1032+
XCTAssertEqual(NSNumber(value: UInt8.max).description, "255")
1033+
XCTAssertEqual(NSNumber(value: UInt16.min).description, "0")
1034+
XCTAssertEqual(NSNumber(value: UInt16.max).description, "65535")
1035+
XCTAssertEqual(NSNumber(value: UInt32.min).description, "0")
1036+
XCTAssertEqual(NSNumber(value: UInt32.max).description, "4294967295")
1037+
XCTAssertEqual(NSNumber(value: UInt64.min).description, "0")
1038+
XCTAssertEqual(NSNumber(value: UInt64.max).description, "18446744073709551615")
10221039
}
1023-
1040+
10241041
func test_descriptionWithLocale() {
1025-
let nsnumber: NSNumber = 1000
1026-
let values : Dictionary = [
1027-
Locale(identifier: "en_GB") : "1,000",
1028-
Locale(identifier: "de_DE") : "1.000",
1029-
]
1030-
for (locale, expectedDesc) in values {
1031-
let receivedDesc = nsnumber.description(withLocale: locale)
1032-
XCTAssertEqual(receivedDesc, expectedDesc, "expected \(expectedDesc) but received \(receivedDesc)")
1033-
}
1042+
// nil Locale
1043+
XCTAssertEqual(NSNumber(value: 1000).description(withLocale: nil), "1000")
1044+
XCTAssertEqual(NSNumber(value: 0.001).description(withLocale: nil), "0.001")
1045+
1046+
XCTAssertEqual(NSNumber(value: Int8.min).description(withLocale: nil), "-128")
1047+
XCTAssertEqual(NSNumber(value: Int8.max).description(withLocale: nil), "127")
1048+
XCTAssertEqual(NSNumber(value: Int16.min).description(withLocale: nil), "-32768")
1049+
XCTAssertEqual(NSNumber(value: Int16.max).description(withLocale: nil), "32767")
1050+
XCTAssertEqual(NSNumber(value: Int32.min).description(withLocale: nil), "-2147483648")
1051+
XCTAssertEqual(NSNumber(value: Int32.max).description(withLocale: nil), "2147483647")
1052+
XCTAssertEqual(NSNumber(value: Int64.min).description(withLocale: nil), "-9223372036854775808")
1053+
XCTAssertEqual(NSNumber(value: Int64.max).description(withLocale: nil), "9223372036854775807")
1054+
1055+
XCTAssertEqual(NSNumber(value: UInt8.min).description(withLocale: nil), "0")
1056+
XCTAssertEqual(NSNumber(value: UInt8.max).description(withLocale: nil), "255")
1057+
XCTAssertEqual(NSNumber(value: UInt16.min).description(withLocale: nil), "0")
1058+
XCTAssertEqual(NSNumber(value: UInt16.max).description(withLocale: nil), "65535")
1059+
XCTAssertEqual(NSNumber(value: UInt32.min).description(withLocale: nil), "0")
1060+
XCTAssertEqual(NSNumber(value: UInt32.max).description(withLocale: nil), "4294967295")
1061+
XCTAssertEqual(NSNumber(value: UInt64.min).description(withLocale: nil), "0")
1062+
XCTAssertEqual(NSNumber(value: UInt64.max).description(withLocale: nil), "18446744073709551615")
1063+
1064+
// en_GB Locale
1065+
XCTAssertEqual(NSNumber(value: 1000).description(withLocale: Locale(identifier: "en_GB")), "1,000")
1066+
XCTAssertEqual(NSNumber(value: 0.001).description(withLocale: Locale(identifier: "en_GB")), "0.001")
1067+
1068+
XCTAssertEqual(NSNumber(value: Int8.min).description(withLocale: Locale(identifier: "en_GB")), "-128")
1069+
XCTAssertEqual(NSNumber(value: Int8.max).description(withLocale: Locale(identifier: "en_GB")), "127")
1070+
XCTAssertEqual(NSNumber(value: Int16.min).description(withLocale: Locale(identifier: "en_GB")), "-32,768")
1071+
XCTAssertEqual(NSNumber(value: Int16.max).description(withLocale: Locale(identifier: "en_GB")), "32,767")
1072+
XCTAssertEqual(NSNumber(value: Int32.min).description(withLocale: Locale(identifier: "en_GB")), "-2,147,483,648")
1073+
XCTAssertEqual(NSNumber(value: Int32.max).description(withLocale: Locale(identifier: "en_GB")), "2,147,483,647")
1074+
XCTAssertEqual(NSNumber(value: Int64.min).description(withLocale: Locale(identifier: "en_GB")), "-9,223,372,036,854,775,808")
1075+
XCTAssertEqual(NSNumber(value: Int64.max).description(withLocale: Locale(identifier: "en_GB")), "9,223,372,036,854,775,807")
1076+
1077+
XCTAssertEqual(NSNumber(value: UInt8.min).description(withLocale: Locale(identifier: "en_GB")), "0")
1078+
XCTAssertEqual(NSNumber(value: UInt8.max).description(withLocale: Locale(identifier: "en_GB")), "255")
1079+
XCTAssertEqual(NSNumber(value: UInt16.min).description(withLocale: Locale(identifier: "en_GB")), "0")
1080+
XCTAssertEqual(NSNumber(value: UInt16.max).description(withLocale: Locale(identifier: "en_GB")), "65,535")
1081+
XCTAssertEqual(NSNumber(value: UInt32.min).description(withLocale: Locale(identifier: "en_GB")), "0")
1082+
XCTAssertEqual(NSNumber(value: UInt32.max).description(withLocale: Locale(identifier: "en_GB")), "4,294,967,295")
1083+
XCTAssertEqual(NSNumber(value: UInt64.min).description(withLocale: Locale(identifier: "en_GB")), "0")
1084+
1085+
// This is the correct value but currently buggy and the locale is not used
1086+
// XCTAssertEqual(NSNumber(value: UInt64.max).description(withLocale: Locale(identifier: "en_GB")), "18,446,744,073,709,551,615")
1087+
XCTAssertEqual(NSNumber(value: UInt64.max).description(withLocale: Locale(identifier: "en_GB")), "18446744073709551615")
1088+
1089+
// de_DE Locale
1090+
XCTAssertEqual(NSNumber(value: 1000).description(withLocale: Locale(identifier: "de_DE")), "1.000")
1091+
XCTAssertEqual(NSNumber(value: 0.001).description(withLocale: Locale(identifier: "de_DE")), "0,001")
1092+
1093+
XCTAssertEqual(NSNumber(value: Int8.min).description(withLocale: Locale(identifier: "de_DE")), "-128")
1094+
XCTAssertEqual(NSNumber(value: Int8.max).description(withLocale: Locale(identifier: "de_DE")), "127")
1095+
XCTAssertEqual(NSNumber(value: Int16.min).description(withLocale: Locale(identifier: "de_DE")), "-32.768")
1096+
XCTAssertEqual(NSNumber(value: Int16.max).description(withLocale: Locale(identifier: "de_DE")), "32.767")
1097+
XCTAssertEqual(NSNumber(value: Int32.min).description(withLocale: Locale(identifier: "de_DE")), "-2.147.483.648")
1098+
XCTAssertEqual(NSNumber(value: Int32.max).description(withLocale: Locale(identifier: "de_DE")), "2.147.483.647")
1099+
XCTAssertEqual(NSNumber(value: Int64.min).description(withLocale: Locale(identifier: "de_DE")), "-9.223.372.036.854.775.808")
1100+
XCTAssertEqual(NSNumber(value: Int64.max).description(withLocale: Locale(identifier: "de_DE")), "9.223.372.036.854.775.807")
1101+
1102+
XCTAssertEqual(NSNumber(value: UInt8.min).description(withLocale: Locale(identifier: "de_DE")), "0")
1103+
XCTAssertEqual(NSNumber(value: UInt8.max).description(withLocale: Locale(identifier: "de_DE")), "255")
1104+
XCTAssertEqual(NSNumber(value: UInt16.min).description(withLocale: Locale(identifier: "de_DE")), "0")
1105+
XCTAssertEqual(NSNumber(value: UInt16.max).description(withLocale: Locale(identifier: "de_DE")), "65.535")
1106+
XCTAssertEqual(NSNumber(value: UInt32.min).description(withLocale: Locale(identifier: "de_DE")), "0")
1107+
XCTAssertEqual(NSNumber(value: UInt32.max).description(withLocale: Locale(identifier: "de_DE")), "4.294.967.295")
1108+
XCTAssertEqual(NSNumber(value: UInt64.min).description(withLocale: Locale(identifier: "de_DE")), "0")
1109+
1110+
// This is the correct value but currently buggy and the locale is not used
1111+
//XCTAssertEqual(NSNumber(value: UInt64.max).description(withLocale: Locale(identifier: "de_DE")), "18.446.744.073.709.551.615")
1112+
XCTAssertEqual(NSNumber(value: UInt64.max).description(withLocale: Locale(identifier: "de_DE")), "18446744073709551615")
10341113
}
10351114

10361115
func test_objCType() {

TestFoundation/TestNSString.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -832,19 +832,17 @@ class TestNSString: LoopbackServerTest {
832832
XCTAssertEqual(string, "Default value is 1000 (42.0)")
833833
}
834834

835-
#if false // these two tests expose bugs in icu4c's localization on some linux builds (disable until we can get a uniform fix for this)
836835
withVaList(argument) {
837836
pointer in
838-
let string = NSString(format: "en_GB value is %d (%.1f)", locale: Locale.init(localeIdentifier: "en_GB"), arguments: pointer)
837+
let string = NSString(format: "en_GB value is %d (%.1f)", locale: Locale.init(identifier: "en_GB") as AnyObject, arguments: pointer)
839838
XCTAssertEqual(string, "en_GB value is 1,000 (42.0)")
840839
}
841840

842841
withVaList(argument) {
843842
pointer in
844-
let string = NSString(format: "de_DE value is %d (%.1f)", locale: Locale.init(localeIdentifier: "de_DE"), arguments: pointer)
843+
let string = NSString(format: "de_DE value is %d (%.1f)", locale: Locale.init(identifier: "de_DE") as AnyObject, arguments: pointer)
845844
XCTAssertEqual(string, "de_DE value is 1.000 (42,0)")
846845
}
847-
#endif
848846

849847
withVaList(argument) {
850848
pointer in

0 commit comments

Comments
 (0)