Merge pull request #684 from e78l/numfmt
NSNumberFormatter implementation progress
diff --git a/Docs/Status.md b/Docs/Status.md
index de77b21..6c0eb68 100644
--- a/Docs/Status.md
+++ b/Docs/Status.md
@@ -47,7 +47,7 @@
|------------------------------|-----------------|---------------|--------------------------------------------------------------------------------------------------------------------|
| `URLAuthenticationChallenge` | Unimplemented | None | |
| `URLCache` | Unimplemented | None | |
- | `URLCredential` | Mostly Complete | Incomplete | `NSCoding` and `NSCopying` remain unimplemented |
+ | `URLCredential` | Mostly Complete | Incomplete | `NSCopying` remains unimplemented |
| `URLCredentialStorage` | Unimplemented | None | |
| `NSURLError*` | Complete | N/A | |
| `URLProtectionSpace` | Unimplemented | None | |
diff --git a/Foundation.xcodeproj/project.pbxproj b/Foundation.xcodeproj/project.pbxproj
index a16ff38..2af4035 100755
--- a/Foundation.xcodeproj/project.pbxproj
+++ b/Foundation.xcodeproj/project.pbxproj
@@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
0383A1751D2E558A0052E5D1 /* TestNSStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0383A1741D2E558A0052E5D1 /* TestNSStream.swift */; };
1520469B1D8AEABE00D02E36 /* HTTPServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1520469A1D8AEABE00D02E36 /* HTTPServer.swift */; };
+ 231503DB1D8AEE5D0061694D /* TestNSDecimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 231503DA1D8AEE5D0061694D /* TestNSDecimal.swift */; };
294E3C1D1CC5E19300E4F44C /* TestNSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294E3C1C1CC5E19300E4F44C /* TestNSAttributedString.swift */; };
2EBE67A51C77BF0E006583D5 /* TestNSDateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBE67A31C77BF05006583D5 /* TestNSDateFormatter.swift */; };
528776141BF2629700CB0090 /* FoundationErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522C253A1BF16E1600804FC6 /* FoundationErrors.swift */; };
@@ -307,6 +308,7 @@
7900433B1CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 790043391CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift */; };
7900433C1CACD33E00ECCBF1 /* TestNSPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7900433A1CACD33E00ECCBF1 /* TestNSPredicate.swift */; };
AE35A1861CBAC85E0042DB84 /* SwiftFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = AE35A1851CBAC85E0042DB84 /* SwiftFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ BF8E65311DC3B3CB005AB5C3 /* TestNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8E65301DC3B3CB005AB5C3 /* TestNotification.swift */; };
CC5249C01D341D23007CB54D /* TestUnitConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC5249BF1D341D23007CB54D /* TestUnitConverter.swift */; };
CE19A88C1C23AA2300B4CB6A /* NSStringTestData.txt in Resources */ = {isa = PBXBuildFile; fileRef = CE19A88B1C23AA2300B4CB6A /* NSStringTestData.txt */; };
D31302011C30CEA900295652 /* NSConcreteValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31302001C30CEA900295652 /* NSConcreteValue.swift */; };
@@ -336,6 +338,7 @@
EA08126B1DA80C3600651B70 /* TestNSProgressFraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA08126A1DA80C3600651B70 /* TestNSProgressFraction.swift */; };
EA08126C1DA810BE00651B70 /* ProgressFraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0812681DA71C8A00651B70 /* ProgressFraction.swift */; };
EA418C261D57257D005EAD0D /* NSKeyedArchiverHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA418C251D57257D005EAD0D /* NSKeyedArchiverHelpers.swift */; };
+ EA54A6FB1DB16D53009E0809 /* TestObjCRuntime.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA54A6FA1DB16D53009E0809 /* TestObjCRuntime.swift */; };
EA66F6361BEED03E00136161 /* TargetConditionals.h in Headers */ = {isa = PBXBuildFile; fileRef = EA66F6351BEED03E00136161 /* TargetConditionals.h */; settings = {ATTRIBUTES = (Public, ); }; };
EA66F6481BF1619600136161 /* NSURLTestData.plist in Resources */ = {isa = PBXBuildFile; fileRef = EA66F63B1BF1619600136161 /* NSURLTestData.plist */; };
EA66F6671BF2F2F100136161 /* CoreFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = EA66F6651BF2F2E800136161 /* CoreFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -455,6 +458,7 @@
0383A1741D2E558A0052E5D1 /* TestNSStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSStream.swift; sourceTree = "<group>"; };
1520469A1D8AEABE00D02E36 /* HTTPServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPServer.swift; sourceTree = "<group>"; };
22B9C1E01C165D7A00DECFF9 /* TestNSDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSDate.swift; sourceTree = "<group>"; };
+ 231503DA1D8AEE5D0061694D /* TestNSDecimal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSDecimal.swift; sourceTree = "<group>"; };
294E3C1C1CC5E19300E4F44C /* TestNSAttributedString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSAttributedString.swift; sourceTree = "<group>"; };
2EBE67A31C77BF05006583D5 /* TestNSDateFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSDateFormatter.swift; sourceTree = "<group>"; };
400E22641C1A4E58007C5933 /* TestNSProcessInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSProcessInfo.swift; sourceTree = "<group>"; };
@@ -741,6 +745,7 @@
88D28DE61C13AE9000494606 /* TestNSGeometry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSGeometry.swift; sourceTree = "<group>"; };
A5A34B551C18C85D00FD972B /* TestNSByteCountFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSByteCountFormatter.swift; sourceTree = "<group>"; };
AE35A1851CBAC85E0042DB84 /* SwiftFoundation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwiftFoundation.h; sourceTree = "<group>"; };
+ BF8E65301DC3B3CB005AB5C3 /* TestNotification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNotification.swift; sourceTree = "<group>"; };
C2A9D75B1C15C08B00993803 /* TestNSUUID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSUUID.swift; sourceTree = "<group>"; };
C93559281C12C49F009FD6A9 /* TestNSAffineTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSAffineTransform.swift; sourceTree = "<group>"; };
CC5249BF1D341D23007CB54D /* TestUnitConverter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUnitConverter.swift; sourceTree = "<group>"; };
@@ -780,6 +785,7 @@
EA313DFE1BE7F2E90060A403 /* CFURLComponents.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFURLComponents.c; sourceTree = "<group>"; };
EA313DFF1BE7F2E90060A403 /* CFURLComponents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFURLComponents.h; sourceTree = "<group>"; };
EA418C251D57257D005EAD0D /* NSKeyedArchiverHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSKeyedArchiverHelpers.swift; sourceTree = "<group>"; };
+ EA54A6FA1DB16D53009E0809 /* TestObjCRuntime.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestObjCRuntime.swift; sourceTree = "<group>"; };
EA66F6351BEED03E00136161 /* TargetConditionals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TargetConditionals.h; path = CoreFoundation/Base.subproj/SwiftRuntime/TargetConditionals.h; sourceTree = SOURCE_ROOT; };
EA66F6381BF1619600136161 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
EA66F63B1BF1619600136161 /* NSURLTestData.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = NSURLTestData.plist; sourceTree = "<group>"; };
@@ -1324,6 +1330,7 @@
DCDBB8321C1768AC00313299 /* TestNSData.swift */,
22B9C1E01C165D7A00DECFF9 /* TestNSDate.swift */,
2EBE67A31C77BF05006583D5 /* TestNSDateFormatter.swift */,
+ 231503DA1D8AEE5D0061694D /* TestNSDecimal.swift */,
EA66F63D1BF1619600136161 /* TestNSDictionary.swift */,
D512D17B1CD883F00032E6A5 /* TestNSFileHandle.swift */,
525AECEB1BF2C96400D15BB0 /* TestNSFileManager.swift */,
@@ -1372,6 +1379,8 @@
5B6F17961C48631C00935030 /* TestUtils.swift */,
0383A1741D2E558A0052E5D1 /* TestNSStream.swift */,
5B1FD9E21D6D17B80080E83C /* TestNSURLSession.swift */,
+ EA54A6FA1DB16D53009E0809 /* TestObjCRuntime.swift */,
+ BF8E65301DC3B3CB005AB5C3 /* TestNotification.swift */,
);
name = Tests;
sourceTree = "<group>";
@@ -2205,9 +2214,11 @@
5B13B3331C582D4C00651CE2 /* TestNSJSONSerialization.swift in Sources */,
5B13B33C1C582D4C00651CE2 /* TestNSOrderedSet.swift in Sources */,
5B13B34A1C582D4C00651CE2 /* TestNSURL.swift in Sources */,
+ EA54A6FB1DB16D53009E0809 /* TestObjCRuntime.swift in Sources */,
5B13B34D1C582D4C00651CE2 /* TestNSUUID.swift in Sources */,
5B13B3281C582D4C00651CE2 /* TestNSBundle.swift in Sources */,
5B13B32A1C582D4C00651CE2 /* TestNSCharacterSet.swift in Sources */,
+ BF8E65311DC3B3CB005AB5C3 /* TestNotification.swift in Sources */,
EA01AAEC1DA839C4008F4E07 /* TestProgress.swift in Sources */,
5B13B3411C582D4C00651CE2 /* TestNSRegularExpression.swift in Sources */,
5B13B3491C582D4C00651CE2 /* TestNSTimeZone.swift in Sources */,
@@ -2216,6 +2227,7 @@
5B13B33E1C582D4C00651CE2 /* TestNSProcessInfo.swift in Sources */,
5B13B33F1C582D4C00651CE2 /* TestNSPropertyList.swift in Sources */,
5B13B32C1C582D4C00651CE2 /* TestNSDate.swift in Sources */,
+ 231503DB1D8AEE5D0061694D /* TestNSDecimal.swift in Sources */,
7900433C1CACD33E00ECCBF1 /* TestNSPredicate.swift in Sources */,
5B13B33B1C582D4C00651CE2 /* TestNSNumberFormatter.swift in Sources */,
5B13B3301C582D4C00651CE2 /* TestNSHTTPCookie.swift in Sources */,
diff --git a/Foundation/CGFloat.swift b/Foundation/CGFloat.swift
index bba73b4..3462d8d 100644
--- a/Foundation/CGFloat.swift
+++ b/Foundation/CGFloat.swift
@@ -145,15 +145,17 @@
public var native: NativeType
}
-@_transparent extension CGFloat : BinaryFloatingPoint {
+extension CGFloat : BinaryFloatingPoint {
public typealias RawSignificand = UInt
public typealias Exponent = Int
-
+
+ @_transparent
public static var exponentBitCount: Int {
return NativeType.exponentBitCount
}
+ @_transparent
public static var significandBitCount: Int {
return NativeType.significandBitCount
}
@@ -161,10 +163,12 @@
// Conversions to/from integer encoding. These are not part of the
// BinaryFloatingPoint prototype because there's no guarantee that an
// integer type of the same size actually exists (e.g. Float80).
+ @_transparent
public var bitPattern: UInt {
return UInt(native.bitPattern)
}
-
+
+ @_transparent
public init(bitPattern: UInt) {
#if arch(i386) || arch(arm)
native = NativeType(bitPattern: UInt32(bitPattern))
@@ -172,19 +176,23 @@
native = NativeType(bitPattern: UInt64(bitPattern))
#endif
}
-
+
+ @_transparent
public var sign: FloatingPointSign {
return native.sign
}
-
+
+ @_transparent
public var exponentBitPattern: UInt {
return native.exponentBitPattern
}
-
+
+ @_transparent
public var significandBitPattern: UInt {
return UInt(native.significandBitPattern)
}
-
+
+ @_transparent
public init(sign: FloatingPointSign,
exponentBitPattern: UInt,
significandBitPattern: UInt) {
@@ -192,177 +200,217 @@
exponentBitPattern: exponentBitPattern,
significandBitPattern: NativeType.RawSignificand(significandBitPattern))
}
-
+
+ @_transparent
public init(nan payload: RawSignificand, signaling: Bool) {
native = NativeType(nan: NativeType.RawSignificand(payload),
signaling: signaling)
}
-
+
+ @_transparent
public static var infinity: CGFloat {
return CGFloat(NativeType.infinity)
}
-
+
+ @_transparent
public static var nan: CGFloat {
return CGFloat(NativeType.nan)
}
-
+
+ @_transparent
public static var signalingNaN: CGFloat {
return CGFloat(NativeType.signalingNaN)
}
-
+
@available(*, unavailable, renamed: "nan")
public static var quietNaN: CGFloat {
fatalError("unavailable")
}
-
+
+ @_transparent
public static var greatestFiniteMagnitude: CGFloat {
return CGFloat(NativeType.greatestFiniteMagnitude)
}
-
+
+ @_transparent
public static var pi: CGFloat {
return CGFloat(NativeType.pi)
}
-
+
+ @_transparent
public var ulp: CGFloat {
return CGFloat(native.ulp)
}
-
+
+ @_transparent
public static var leastNormalMagnitude: CGFloat {
return CGFloat(NativeType.leastNormalMagnitude)
}
-
+
+ @_transparent
public static var leastNonzeroMagnitude: CGFloat {
return CGFloat(NativeType.leastNonzeroMagnitude)
}
-
+
+ @_transparent
public var exponent: Int {
return native.exponent
}
-
+
+ @_transparent
public var significand: CGFloat {
return CGFloat(native.significand)
}
-
+
+ @_transparent
public init(sign: FloatingPointSign, exponent: Int, significand: CGFloat) {
native = NativeType(sign: sign,
exponent: exponent, significand: significand.native)
}
-
+
+ @_transparent
public mutating func round(_ rule: FloatingPointRoundingRule) {
native.round(rule)
}
-
+
+ @_transparent
public var nextUp: CGFloat {
return CGFloat(native.nextUp)
}
-
+
+ @_transparent
public var magnitude: CGFloat {
return CGFloat(Swift.abs(native))
}
-
+
+ @_transparent
public mutating func negate() {
native.negate()
}
-
+
+ @_transparent
public mutating func add(_ other: CGFloat) {
native.add(other.native)
}
-
+
+ @_transparent
public mutating func subtract(_ other: CGFloat) {
native.subtract(other.native)
}
-
+
+ @_transparent
public mutating func multiply(by other: CGFloat) {
native.multiply(by: other.native)
}
-
+
+ @_transparent
public mutating func divide(by other: CGFloat) {
native.divide(by: other.native)
}
-
+
+ @_transparent
public mutating func formTruncatingRemainder(dividingBy other: CGFloat) {
native.formTruncatingRemainder(dividingBy: other.native)
}
-
+
+ @_transparent
public mutating func formRemainder(dividingBy other: CGFloat) {
native.formRemainder(dividingBy: other.native)
}
-
+
+ @_transparent
public mutating func formSquareRoot( ) {
native.formSquareRoot( )
}
-
+
+ @_transparent
public mutating func addProduct(_ lhs: CGFloat, _ rhs: CGFloat) {
native.addProduct(lhs.native, rhs.native)
}
-
+
+ @_transparent
public func isEqual(to other: CGFloat) -> Bool {
return self.native.isEqual(to: other.native)
}
-
+
+ @_transparent
public func isLess(than other: CGFloat) -> Bool {
return self.native.isLess(than: other.native)
}
-
+
+ @_transparent
public func isLessThanOrEqualTo(_ other: CGFloat) -> Bool {
return self.native.isLessThanOrEqualTo(other.native)
}
-
+
+ @_transparent
public var isNormal: Bool {
return native.isNormal
}
-
+
+ @_transparent
public var isFinite: Bool {
return native.isFinite
}
-
+
+ @_transparent
public var isZero: Bool {
return native.isZero
}
-
+
+ @_transparent
public var isSubnormal: Bool {
return native.isSubnormal
}
-
+
+ @_transparent
public var isInfinite: Bool {
return native.isInfinite
}
-
+
+ @_transparent
public var isNaN: Bool {
return native.isNaN
}
-
+
+ @_transparent
public var isSignalingNaN: Bool {
return native.isSignalingNaN
}
-
+
@available(*, unavailable, renamed: "isSignalingNaN")
public var isSignaling: Bool {
fatalError("unavailable")
}
-
+
+ @_transparent
public var isCanonical: Bool {
return true
}
-
+
+ @_transparent
public var floatingPointClass: FloatingPointClassification {
return native.floatingPointClass
}
-
+
+ @_transparent
public var binade: CGFloat {
return CGFloat(native.binade)
}
-
+
+ @_transparent
public var significandWidth: Int {
return native.significandWidth
}
-
+
/// Create an instance initialized to `value`.
+ @_transparent
public init(floatLiteral value: NativeType) {
native = value
}
-
+
/// Create an instance initialized to `value`.
+ @_transparent
public init(integerLiteral value: Int) {
native = NativeType(value)
}
@@ -402,14 +450,14 @@
}
}
-@_transparent extension CGFloat : CustomStringConvertible {
+extension CGFloat : CustomStringConvertible {
/// A textual representation of `self`.
public var description: String {
return native.description
}
}
-@_transparent extension CGFloat : Hashable {
+extension CGFloat : Hashable {
/// The hash value.
///
/// **Axiom:** `x == y` implies `x.hashValue == y.hashValue`
@@ -417,78 +465,91 @@
/// - Note: the hash value is not guaranteed to be stable across
/// different invocations of the same program. Do not persist the
/// hash value across program runs.
+ @_transparent
public var hashValue: Int {
return native.hashValue
}
}
-@_transparent extension UInt8 {
+extension UInt8 {
+ @_transparent
public init(_ value: CGFloat) {
self = UInt8(value.native)
}
}
-@_transparent extension Int8 {
+extension Int8 {
+ @_transparent
public init(_ value: CGFloat) {
self = Int8(value.native)
}
}
-@_transparent extension UInt16 {
+extension UInt16 {
+ @_transparent
public init(_ value: CGFloat) {
self = UInt16(value.native)
}
}
-@_transparent extension Int16 {
+extension Int16 {
+ @_transparent
public init(_ value: CGFloat) {
self = Int16(value.native)
}
}
-@_transparent extension UInt32 {
+extension UInt32 {
+ @_transparent
public init(_ value: CGFloat) {
self = UInt32(value.native)
}
}
-@_transparent extension Int32 {
+extension Int32 {
+ @_transparent
public init(_ value: CGFloat) {
self = Int32(value.native)
}
}
-@_transparent extension UInt64 {
+extension UInt64 {
+ @_transparent
public init(_ value: CGFloat) {
self = UInt64(value.native)
}
}
-@_transparent extension Int64 {
+extension Int64 {
+ @_transparent
public init(_ value: CGFloat) {
self = Int64(value.native)
}
}
-@_transparent extension UInt {
+extension UInt {
+ @_transparent
public init(_ value: CGFloat) {
self = UInt(value.native)
}
}
-@_transparent extension Int {
+extension Int {
+ @_transparent
public init(_ value: CGFloat) {
self = Int(value.native)
}
}
-@_transparent extension Double {
+extension Double {
+ @_transparent
public init(_ value: CGFloat) {
self = Double(value.native)
}
}
-@_transparent extension Float {
+extension Float {
+ @_transparent
public init(_ value: CGFloat) {
self = Float(value.native)
}
@@ -547,7 +608,7 @@
// Strideable Conformance
//===----------------------------------------------------------------------===//
-@_transparent extension CGFloat : Strideable {
+extension CGFloat : Strideable {
/// Returns a stride `x` such that `self.advanced(by: x)` approximates
/// `other`.
///
@@ -571,41 +632,35 @@
// Deprecated operators
//===----------------------------------------------------------------------===//
-@_transparent
@available(*, unavailable, message: "use += 1")
@discardableResult
public prefix func ++(rhs: inout CGFloat) -> CGFloat {
fatalError("++ is not available")
}
-@_transparent
@available(*, unavailable, message: "use -= 1")
@discardableResult
public prefix func --(rhs: inout CGFloat) -> CGFloat {
fatalError("-- is not available")
}
-@_transparent
@available(*, unavailable, message: "use += 1")
@discardableResult
public postfix func ++(lhs: inout CGFloat) -> CGFloat {
fatalError("++ is not available")
}
-@_transparent
@available(*, unavailable, message: "use -= 1")
@discardableResult
public postfix func --(lhs: inout CGFloat) -> CGFloat {
fatalError("-- is not available")
}
-@_transparent
@available(*, unavailable, message: "Use truncatingRemainder instead")
public func %(lhs: CGFloat, rhs: CGFloat) -> CGFloat {
fatalError("% is not available.")
}
-@_transparent
@available(*, unavailable, message: "Use formTruncatingRemainder instead")
public func %=(lhs: inout CGFloat, rhs: CGFloat) {
fatalError("%= is not available.")
@@ -880,16 +935,17 @@
return CGFloat(yn(n, Double(x.native)))
}
-@_transparent
extension CGFloat : _CVarArgPassedAsDouble, _CVarArgAligned {
/// Transform `self` into a series of machine words that can be
/// appropriately interpreted by C varargs
+ @_transparent
public var _cVarArgEncoding: [Int] {
return native._cVarArgEncoding
}
/// Return the required alignment in bytes of
/// the value returned by `_cVarArgEncoding`.
+ @_transparent
public var _cVarArgAlignment: Int {
return native._cVarArgAlignment
}
diff --git a/Foundation/CharacterSet.swift b/Foundation/CharacterSet.swift
index 4babf01..35fbe72 100644
--- a/Foundation/CharacterSet.swift
+++ b/Foundation/CharacterSet.swift
@@ -13,6 +13,10 @@
private func _utfRangeToNSRange(_ inRange : Range<UnicodeScalar>) -> NSRange {
return NSMakeRange(Int(inRange.lowerBound.value), Int(inRange.upperBound.value - inRange.lowerBound.value))
}
+
+private func _utfRangeToNSRange(_ inRange : ClosedRange<UnicodeScalar>) -> NSRange {
+ return NSMakeRange(Int(inRange.lowerBound.value), Int(inRange.upperBound.value - inRange.lowerBound.value + 1))
+}
internal final class _SwiftNSCharacterSet : NSCharacterSet, _SwiftNativeFoundationType {
internal typealias ImmutableType = NSCharacterSet
@@ -129,8 +133,7 @@
///
/// It is the caller's responsibility to ensure that the values represent valid `UnicodeScalar` values, if that is what is desired.
public init(charactersIn range: ClosedRange<UnicodeScalar>) {
- let halfOpenRange = range.lowerBound..<UnicodeScalar(range.upperBound.value + 1)!
- _wrapped = _SwiftNSCharacterSet(immutableObject: NSCharacterSet(range: _utfRangeToNSRange(halfOpenRange)))
+ _wrapped = _SwiftNSCharacterSet(immutableObject: NSCharacterSet(range: _utfRangeToNSRange(range)))
}
/// Initialize with the characters in the given string.
@@ -320,8 +323,7 @@
///
/// It is the caller's responsibility to ensure that the values represent valid `UnicodeScalar` values, if that is what is desired.
public mutating func insert(charactersIn range: ClosedRange<UnicodeScalar>) {
- let halfOpenRange = range.lowerBound..<UnicodeScalar(range.upperBound.value + 1)!
- let nsRange = _utfRangeToNSRange(halfOpenRange)
+ let nsRange = _utfRangeToNSRange(range)
_applyUnmanagedMutation {
$0.addCharacters(in: nsRange)
}
@@ -337,8 +339,7 @@
/// Remove a closed range of integer values from the `CharacterSet`.
public mutating func remove(charactersIn range: ClosedRange<UnicodeScalar>) {
- let halfOpenRange = range.lowerBound..<UnicodeScalar(range.upperBound.value + 1)!
- let nsRange = _utfRangeToNSRange(halfOpenRange)
+ let nsRange = _utfRangeToNSRange(range)
_applyUnmanagedMutation {
$0.removeCharacters(in: nsRange)
}
diff --git a/Foundation/Locale.swift b/Foundation/Locale.swift
index ffe584a..46642ac 100644
--- a/Foundation/Locale.swift
+++ b/Foundation/Locale.swift
@@ -69,7 +69,7 @@
/// Returns a localized string for a specified identifier.
///
- /// For example, in the "en" locale, the result for `"en"` is `"Spanish"`.
+ /// For example, in the "en" locale, the result for `"es"` is `"Spanish"`.
public func localizedString(forIdentifier identifier: String) -> String? {
return _wrapped.displayName(forKey: .identifier, value: identifier)
}
@@ -83,7 +83,7 @@
/// Returns a localized string for a specified region code.
///
- /// For example, in the "en" locale, the result for `"fr"` is `"French"`.
+ /// For example, in the "en" locale, the result for `"fr"` is `"France"`.
public func localizedString(forRegionCode regionCode: String) -> String? {
return _wrapped.displayName(forKey: .countryCode, value: regionCode)
}
diff --git a/Foundation/NSCFString.swift b/Foundation/NSCFString.swift
index e12e0fa..4558549 100644
--- a/Foundation/NSCFString.swift
+++ b/Foundation/NSCFString.swift
@@ -140,19 +140,18 @@
}
internal func _CFSwiftStringGetBytes(_ str: AnyObject, encoding: CFStringEncoding, range: CFRange, buffer: UnsafeMutablePointer<UInt8>?, maxBufLen: CFIndex, usedBufLen: UnsafeMutablePointer<CFIndex>?) -> CFIndex {
+ let convertedLength: CFIndex
switch encoding {
// TODO: Don't treat many encodings like they are UTF8
case CFStringEncoding(kCFStringEncodingUTF8), CFStringEncoding(kCFStringEncodingISOLatin1), CFStringEncoding(kCFStringEncodingMacRoman), CFStringEncoding(kCFStringEncodingASCII), CFStringEncoding(kCFStringEncodingNonLossyASCII):
- let encodingView = (str as! NSString)._swiftObject.utf8
- let start = encodingView.startIndex
+ let encodingView = (str as! NSString).substring(with: NSRange(range)).utf8
if let buffer = buffer {
- for idx in 0..<range.length {
- let characterIndex = encodingView.index(start, offsetBy: idx + range.location)
- let character = encodingView[characterIndex]
+ for (idx, character) in encodingView.enumerated() {
buffer.advanced(by: idx).initialize(to: character)
}
}
- usedBufLen?.pointee = range.length
+ usedBufLen?.pointee = encodingView.count
+ convertedLength = encodingView.count
case CFStringEncoding(kCFStringEncodingUTF16):
let encodingView = (str as! NSString)._swiftObject.utf16
@@ -169,13 +168,13 @@
}
// Every character was 2 bytes
usedBufLen?.pointee = range.length * 2
-
+ convertedLength = range.length
default:
fatalError("Attempted to get bytes of a Swift string using an unsupported encoding")
}
- return range.length
+ return convertedLength
}
internal func _CFSwiftStringCreateWithSubstring(_ str: AnyObject, range: CFRange) -> Unmanaged<AnyObject> {
diff --git a/Foundation/NSDecimal.swift b/Foundation/NSDecimal.swift
index 470c55e..dcba6f4 100644
--- a/Foundation/NSDecimal.swift
+++ b/Foundation/NSDecimal.swift
@@ -1,155 +1,1905 @@
// This source file is part of the Swift.org open source project
//
-// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Copyright (c) 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
-public var NSDecimalMaxSize: Int32 { NSUnimplemented() }
+import CoreFoundation
+
+public var NSDecimalMaxSize: Int32 { return 8 }
// Give a precision of at least 38 decimal digits, 128 binary positions.
-public var NSDecimalNoScale: Int32 { NSUnimplemented() }
+public var NSDecimalNoScale: Int32 { return Int32(Int16.max) }
public struct Decimal {
- public var _exponent: Int32
- public var _length: UInt32 // length == 0 && isNegative -> NaN
- public var _isNegative: UInt32
- public var _isCompact: UInt32
- public var _reserved: UInt32
+ fileprivate static let maxSize: UInt32 = UInt32(NSDecimalMaxSize)
+ fileprivate var __exponent: Int8
+ fileprivate var __lengthAndFlags: UInt8
+ fileprivate var __reserved: UInt16
+ public var _exponent: Int32 {
+ get {
+ return Int32(__exponent)
+ }
+ set {
+ __exponent = Int8(truncatingBitPattern: newValue)
+ }
+ }
+ // length == 0 && isNegative -> NaN
+ public var _length: UInt32 {
+ get {
+ return UInt32((__lengthAndFlags & 0b0000_1111))
+ }
+ set {
+ guard newValue <= maxMantissaLength else {
+ fatalError("Attempt to set a length greater than capacity \(newValue) > \(maxMantissaLength)")
+ }
+ __lengthAndFlags =
+ (__lengthAndFlags & 0b1111_0000) |
+ UInt8(newValue & 0b0000_1111)
+ }
+ }
+ public var _isNegative: UInt32 {
+ get {
+ return UInt32(((__lengthAndFlags) & 0b0001_0000) >> 4)
+ }
+ set {
+ __lengthAndFlags =
+ (__lengthAndFlags & 0b1110_1111) |
+ (UInt8(newValue & 0b0000_0001 ) << 4)
+ }
+ }
+ public var _isCompact: UInt32 {
+ get {
+ return UInt32(((__lengthAndFlags) & 0b0010_0000) >> 5)
+ }
+ set {
+ __lengthAndFlags =
+ (__lengthAndFlags & 0b1101_1111) |
+ (UInt8(newValue & 0b0000_00001 ) << 5)
+ }
+ }
+ public var _reserved: UInt32 {
+ get {
+ return UInt32(UInt32(__lengthAndFlags & 0b1100_0000) << 10 | UInt32(__reserved))
+ }
+ set {
+ __lengthAndFlags =
+ (__lengthAndFlags & 0b0011_1111) |
+ UInt8(UInt32(newValue & (0b11 << 16)) >> 10)
+ __reserved = UInt16(newValue & 0b1111_1111_1111_1111)
+ }
+ }
public var _mantissa: (UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16)
- public init() { NSUnimplemented() }
- public init(_exponent: Int32, _length: UInt32, _isNegative: UInt32, _isCompact: UInt32, _reserved: UInt32, _mantissa: (UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16)){ NSUnimplemented() }
+ public init() {
+ self._mantissa = (0,0,0,0,0,0,0,0)
+ self.__exponent = 0
+ self.__lengthAndFlags = 0
+ self.__reserved = 0
+ }
+
+ fileprivate init(length: UInt32, mantissa: (UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16)) {
+ self._mantissa = mantissa
+ self.__exponent = 0
+ self.__lengthAndFlags = 0
+ self.__reserved = 0
+ self._length = length
+ }
+
+ public init(_exponent: Int32, _length: UInt32, _isNegative: UInt32, _isCompact: UInt32, _reserved: UInt32, _mantissa: (UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16)){
+ self._mantissa = _mantissa
+ self.__exponent = Int8(truncatingBitPattern: _exponent)
+ self.__lengthAndFlags = UInt8(_length & 0b1111)
+ self.__reserved = 0
+ self._isNegative = _isNegative
+ self._isCompact = _isCompact
+ self._reserved = _reserved
+ }
}
extension Decimal {
- // These will need to be `let`s when implemented for Foundation API compatibility
- public static var leastFiniteMagnitude: Decimal { NSUnimplemented() }
- public static var greatestFiniteMagnitude: Decimal { NSUnimplemented() }
- public static var leastNormalMagnitude: Decimal { NSUnimplemented() }
- public static var leastNonzeroMagnitude: Decimal { NSUnimplemented() }
- public static var pi: Decimal { NSUnimplemented() }
- public var exponent: Int { NSUnimplemented() }
- public var significand: Decimal { NSUnimplemented() }
- public init(sign: FloatingPointSign, exponent: Int, significand: Decimal) { NSUnimplemented() }
- public init(signOf: Decimal, magnitudeOf magnitude: Decimal) { NSUnimplemented() }
- public var sign: FloatingPointSign { NSUnimplemented() }
- public static var radix: Int { NSUnimplemented() }
- public var ulp: Decimal { NSUnimplemented() }
- public mutating func add(_ other: Decimal) { NSUnimplemented() }
- public mutating func subtract(_ other: Decimal) { NSUnimplemented() }
- public mutating func multiply(by other: Decimal) { NSUnimplemented() }
- public mutating func divide(by other: Decimal) { NSUnimplemented() }
- public mutating func negate() { NSUnimplemented() }
- public func isEqual(to other: Decimal) -> Bool { NSUnimplemented() }
- public func isLess(than other: Decimal) -> Bool { NSUnimplemented() }
- public func isLessThanOrEqualTo(_ other: Decimal) -> Bool { NSUnimplemented() }
- public func isTotallyOrdered(belowOrEqualTo other: Decimal) -> Bool { NSUnimplemented() }
- public var isCanonical: Bool { NSUnimplemented() }
- public var nextUp: Decimal { NSUnimplemented() }
- public var nextDown: Decimal { NSUnimplemented() }
- public static func +(lhs: Decimal, rhs: Decimal) -> Decimal { NSUnimplemented() }
- public static func -(lhs: Decimal, rhs: Decimal) -> Decimal { NSUnimplemented() }
- public static func /(lhs: Decimal, rhs: Decimal) -> Decimal { NSUnimplemented() }
- public static func *(lhs: Decimal, rhs: Decimal) -> Decimal { NSUnimplemented() }
+ public static let leastFiniteMagnitude = Decimal(
+ _exponent: 127,
+ _length: 8,
+ _isNegative: 1,
+ _isCompact: 1,
+ _reserved: 0,
+ _mantissa: (0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)
+ )
+ public static let greatestFiniteMagnitude = Decimal(
+ _exponent: 127,
+ _length: 8,
+ _isNegative: 0,
+ _isCompact: 1,
+ _reserved: 0,
+ _mantissa: (0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff)
+ )
+ public static let leastNormalMagnitude = Decimal(
+ _exponent: -127,
+ _length: 1,
+ _isNegative: 0,
+ _isCompact: 1,
+ _reserved: 0,
+ _mantissa: (0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000)
+ )
+ public static let leastNonzeroMagnitude = Decimal(
+ _exponent: -127,
+ _length: 1,
+ _isNegative: 0,
+ _isCompact: 1,
+ _reserved: 0,
+ _mantissa: (0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000)
+ )
+ public static let pi = Decimal(
+ _exponent: -38,
+ _length: 8,
+ _isNegative: 0,
+ _isCompact: 1,
+ _reserved: 0,
+ _mantissa: (0x6623, 0x7d57, 0x16e7, 0xad0d, 0xaf52, 0x4641, 0xdfa7, 0xec58)
+ )
+ public var exponent: Int {
+ get {
+ return Int(self.__exponent)
+ }
+ }
+ public var significand: Decimal {
+ get {
+ return Decimal(_exponent: 0, _length: _length, _isNegative: _isNegative, _isCompact: _isCompact, _reserved: 0, _mantissa: _mantissa)
+ }
+ }
+ public init(sign: FloatingPointSign, exponent: Int, significand: Decimal) {
+ self.init(_exponent: Int32(exponent) + significand._exponent, _length: significand._length, _isNegative: sign == .plus ? 0 : 1, _isCompact: significand._isCompact, _reserved: 0, _mantissa: significand._mantissa)
+ }
+ public init(signOf: Decimal, magnitudeOf magnitude: Decimal) {
+ self.init(_exponent: magnitude._exponent, _length: magnitude._length, _isNegative: signOf._isNegative, _isCompact: magnitude._isCompact, _reserved: 0, _mantissa: magnitude._mantissa)
+ }
+ public var sign: FloatingPointSign {
+ return _isNegative == 0 ? FloatingPointSign.plus : FloatingPointSign.minus
+ }
+ public static var radix: Int {
+ return 10
+ }
+ public var ulp: Decimal {
+ if !self.isFinite { return Decimal.nan }
+ return Decimal(_exponent: _exponent, _length: 8, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000))
+ }
+ public mutating func add(_ other: Decimal) {
+ var rhs = other
+ _ = NSDecimalAdd(&self, &self, &rhs, .plain)
+ }
+ public mutating func subtract(_ other: Decimal) {
+ var rhs = other
+ _ = NSDecimalSubtract(&self, &self, &rhs, .plain)
+ }
+ public mutating func multiply(by other: Decimal) {
+ var rhs = other
+ _ = NSDecimalMultiply(&self, &self, &rhs, .plain)
+ }
+ public mutating func divide(by other: Decimal) {
+ var rhs = other
+ _ = NSDecimalDivide(&self, &self, &rhs, .plain)
+ }
+ public mutating func negate() {
+ _isNegative = _isNegative == 0 ? 1 : 0
+ }
+ public func isEqual(to other: Decimal) -> Bool {
+ return self.compare(to: other) == .orderedSame
+ }
+ public func isLess(than other: Decimal) -> Bool {
+ return self.compare(to: other) == .orderedAscending
+ }
+ public func isLessThanOrEqualTo(_ other: Decimal) -> Bool {
+ let comparison = self.compare(to: other)
+ return comparison == .orderedAscending || comparison == .orderedSame
+ }
+ public func isTotallyOrdered(belowOrEqualTo other: Decimal) -> Bool {
+ // Notes: Decimal does not have -0 or infinities to worry about
+ if self.isNaN {
+ return false
+ } else if self < other {
+ return true
+ } else if other < self {
+ return false
+ }
+ // fall through to == behavior
+ return true
+ }
+ public var isCanonical: Bool {
+ return true
+ }
+ public var nextUp: Decimal {
+ return self + Decimal(_exponent: _exponent, _length: 1, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000))
+ }
+ public var nextDown: Decimal {
+ return self - Decimal(_exponent: _exponent, _length: 1, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000))
+ }
+ public static func +(lhs: Decimal, rhs: Decimal) -> Decimal {
+ var answer = lhs
+ answer.add(rhs)
+ return answer;
+ }
+ public static func -(lhs: Decimal, rhs: Decimal) -> Decimal {
+ var answer = lhs
+ answer.subtract(rhs)
+ return answer;
+ }
+ public static func /(lhs: Decimal, rhs: Decimal) -> Decimal {
+ var answer = lhs
+ answer.divide(by: rhs)
+ return answer;
+ }
+ public static func *(lhs: Decimal, rhs: Decimal) -> Decimal {
+ var answer = lhs
+ answer.multiply(by: rhs)
+ return answer;
+ }
}
extension Decimal : Hashable, Comparable {
- public var hashValue: Int { NSUnimplemented() }
- public static func ==(lhs: Decimal, rhs: Decimal) -> Bool { NSUnimplemented() }
- public static func <(lhs: Decimal, rhs: Decimal) -> Bool { NSUnimplemented() }
+ internal var doubleValue: Double {
+ var d = 0.0
+ if _length == 0 && _isNegative == 0 {
+ return Double.nan
+ }
+ for i in 0..<8 {
+ let index = 8 - i - 1
+ switch index {
+ case 0:
+ d = d * 65536 + Double(_mantissa.0)
+ break
+ case 1:
+ d = d * 65536 + Double(_mantissa.1)
+ break
+ case 2:
+ d = d * 65536 + Double(_mantissa.2)
+ break
+ case 3:
+ d = d * 65536 + Double(_mantissa.3)
+ break
+ case 4:
+ d = d * 65536 + Double(_mantissa.4)
+ break
+ case 5:
+ d = d * 65536 + Double(_mantissa.5)
+ break
+ case 6:
+ d = d * 65536 + Double(_mantissa.6)
+ break
+ case 7:
+ d = d * 65536 + Double(_mantissa.7)
+ break
+ default:
+ fatalError("conversion overflow")
+ }
+ }
+ if _exponent < 0 {
+ for _ in _exponent..<0 {
+ d /= 10.0
+ }
+ } else {
+ for _ in 0..<_exponent {
+ d *= 10.0
+ }
+ }
+ return _isNegative != 0 ? -d : d
+ }
+ public var hashValue: Int {
+ return Int(bitPattern: __CFHashDouble(doubleValue))
+ }
+ public static func ==(lhs: Decimal, rhs: Decimal) -> Bool {
+ if lhs.isNaN {
+ return rhs.isNaN
+ }
+ if lhs.__exponent == rhs.__exponent && lhs.__lengthAndFlags == rhs.__lengthAndFlags && lhs.__reserved == rhs.__reserved {
+ if lhs._mantissa.0 == rhs._mantissa.0 &&
+ lhs._mantissa.1 == rhs._mantissa.1 &&
+ lhs._mantissa.2 == rhs._mantissa.2 &&
+ lhs._mantissa.3 == rhs._mantissa.3 &&
+ lhs._mantissa.4 == rhs._mantissa.4 &&
+ lhs._mantissa.5 == rhs._mantissa.5 &&
+ lhs._mantissa.6 == rhs._mantissa.6 &&
+ lhs._mantissa.7 == rhs._mantissa.7 {
+ return true
+ }
+ }
+ var lhsVal = lhs
+ var rhsVal = rhs
+ return NSDecimalCompare(&lhsVal, &rhsVal) == .orderedSame
+ }
+ public static func <(lhs: Decimal, rhs: Decimal) -> Bool {
+ var lhsVal = lhs
+ var rhsVal = rhs
+ return NSDecimalCompare(&lhsVal, &rhsVal) == .orderedAscending
+ }
}
extension Decimal : ExpressibleByFloatLiteral {
- public init(floatLiteral value: Double) { NSUnimplemented() }
+ public init(floatLiteral value: Double) {
+ self.init(value)
+ }
}
extension Decimal : ExpressibleByIntegerLiteral {
- public init(integerLiteral value: Int) { NSUnimplemented() }
+ public init(integerLiteral value: Int) {
+ self.init(value)
+ }
}
extension Decimal : SignedNumber {
}
extension Decimal : Strideable {
- public func distance(to other: Decimal) -> Decimal { NSUnimplemented() }
- public func advanced(by n: Decimal) -> Decimal { NSUnimplemented() }
+ public func distance(to other: Decimal) -> Decimal {
+ return self - other
+ }
+ public func advanced(by n: Decimal) -> Decimal {
+ return self + n
+ }
}
extension Decimal : AbsoluteValuable {
- public static func abs(_ x: Decimal) -> Decimal { NSUnimplemented() }
+ public static func abs(_ x: Decimal) -> Decimal {
+ return Decimal(_exponent: x._exponent, _length: x._length, _isNegative: 0, _isCompact: x._isCompact, _reserved: 0, _mantissa: x._mantissa)
+ }
}
extension Decimal {
public typealias RoundingMode = NSDecimalNumber.RoundingMode
public typealias CalculationError = NSDecimalNumber.CalculationError
- public init(_ value: UInt8) { NSUnimplemented() }
- public init(_ value: Int8) { NSUnimplemented() }
- public init(_ value: UInt16) { NSUnimplemented() }
- public init(_ value: Int16) { NSUnimplemented() }
- public init(_ value: UInt32) { NSUnimplemented() }
- public init(_ value: Int32) { NSUnimplemented() }
- public init(_ value: Double) { NSUnimplemented() }
- public init(_ value: UInt64) { NSUnimplemented() }
- public init(_ value: Int64) { NSUnimplemented() }
- public init(_ value: UInt) { NSUnimplemented() }
- public init(_ value: Int) { NSUnimplemented() }
- public var isSignalingNaN: Bool { NSUnimplemented() }
- public static var nan: Decimal { NSUnimplemented() }
- public static var quietNaN: Decimal { NSUnimplemented() }
- public var floatingPointClass: FloatingPointClassification { NSUnimplemented() }
- public var isSignMinus: Bool { NSUnimplemented() }
- public var isNormal: Bool { NSUnimplemented() }
- public var isFinite: Bool { NSUnimplemented() }
- public var isZero: Bool { NSUnimplemented() }
- public var isSubnormal: Bool { NSUnimplemented() }
- public var isInfinite: Bool { NSUnimplemented() }
- public var isNaN: Bool { NSUnimplemented() }
- public var isSignaling: Bool { NSUnimplemented() }
+ public init(_ value: UInt8) {
+ self.init(UInt64(value))
+ }
+ public init(_ value: Int8) {
+ self.init(Int64(value))
+ }
+ public init(_ value: UInt16) {
+ self.init(UInt64(value))
+ }
+ public init(_ value: Int16) {
+ self.init(Int64(value))
+ }
+ public init(_ value: UInt32) {
+ self.init(UInt64(value))
+ }
+ public init(_ value: Int32) {
+ self.init(Int64(value))
+ }
+ public init(_ value: Double) {
+ if value.isNaN {
+ self = Decimal.nan
+ } else if value == 0.0 {
+ self = Decimal()
+ } else {
+ self = Decimal()
+ let negative = value < 0
+ var val = negative ? -1 * value : value
+ var exponent = 0
+ while val < Double(UInt64.max - 1) {
+ val *= 10.0
+ exponent -= 1
+ }
+ while Double(UInt64.max - 1) < val {
+ val /= 10.0
+ exponent += 1
+ }
+ var mantissa = UInt64(val)
+
+ var i = Int32(0)
+ // this is a bit ugly but it is the closest approximation of the C initializer that can be expressed here.
+ while mantissa != 0 && i < NSDecimalMaxSize {
+ switch i {
+ case 0:
+ _mantissa.0 = UInt16(truncatingBitPattern:mantissa)
+ break
+ case 1:
+ _mantissa.1 = UInt16(truncatingBitPattern:mantissa)
+ break
+ case 2:
+ _mantissa.2 = UInt16(truncatingBitPattern:mantissa)
+ break
+ case 3:
+ _mantissa.3 = UInt16(truncatingBitPattern:mantissa)
+ break
+ case 4:
+ _mantissa.4 = UInt16(truncatingBitPattern:mantissa)
+ break
+ case 5:
+ _mantissa.5 = UInt16(truncatingBitPattern:mantissa)
+ break
+ case 6:
+ _mantissa.6 = UInt16(truncatingBitPattern:mantissa)
+ break
+ case 7:
+ _mantissa.7 = UInt16(truncatingBitPattern:mantissa)
+ break
+ default:
+ fatalError("initialization overflow")
+ }
+ mantissa = mantissa >> 16
+ i += 1
+ }
+ _length = UInt32(i)
+ _isNegative = negative ? 1 : 0
+ _isCompact = 0
+ _exponent = Int32(exponent)
+ self.compact()
+ }
+ }
+ public init(_ value: UInt64) {
+ self.init(Double(value))
+ }
+ public init(_ value: Int64) {
+ self.init(Double(value))
+ }
+ public init(_ value: UInt) {
+ self.init(UInt64(value))
+ }
+ public init(_ value: Int) {
+ self.init(Int64(value))
+ }
+ public var isSignalingNaN: Bool {
+ return false
+ }
+ public static var nan: Decimal {
+ return quietNaN
+ }
+ public static var quietNaN: Decimal {
+ var quiet = Decimal()
+ quiet._isNegative = 1
+ return quiet
+ }
+ public var floatingPointClass: FloatingPointClassification {
+ if _length == 0 && _isNegative == 1 {
+ return .quietNaN
+ } else if _length == 0 {
+ return .positiveZero
+ }
+ if _isNegative == 1 {
+ return .negativeNormal
+ } else {
+ return .positiveNormal
+ }
+ }
+ public var isSignMinus: Bool {
+ return _isNegative != 0
+ }
+ public var isNormal: Bool {
+ return !isZero && !isInfinite && !isNaN
+ }
+ public var isFinite: Bool {
+ return !isNaN
+ }
+ public var isZero: Bool {
+ return _length == 0 && _isNegative == 0
+ }
+ public var isSubnormal: Bool {
+ return false
+ }
+ public var isInfinite: Bool {
+ return false
+ }
+ public var isNaN: Bool {
+ return _length == 0 && _isNegative == 1
+ }
+ public var isSignaling: Bool {
+ return false
+ }
}
extension Decimal : CustomStringConvertible {
public init?(string: String, locale: Locale? = nil) {
- // Avoid a compiler warning for now by not calling NSUnimplemented
- return nil
+ let scan = Scanner(string: string)
+ var theDecimal = Decimal()
+ if !scan.scanDecimal(&theDecimal) {
+ return nil
+ }
+ self = theDecimal
}
- public var description: String { NSUnimplemented() }
+ public var description: String {
+ if self.isNaN {
+ return "NaN"
+ }
+ if _length == 0 {
+ return "0"
+ }
+ var copy = self
+ let ZERO : CChar = 0x30 // ASCII '0' == 0x30
+ let decimalChar : CChar = 0x2e // ASCII '.' == 0x2e
+ let MINUS : CChar = 0x2d // ASCII '-' == 0x2d
+
+ let bufferSize = 200 // max value : 39+128+sign+decimalpoint
+ var buffer = Array<CChar>(repeating: 0, count: bufferSize)
+
+ var i = bufferSize - 1
+ while copy._exponent > 0 {
+ i -= 1
+ buffer[i] = ZERO
+ copy._exponent -= 1
+ }
+
+ if copy._exponent == 0 {
+ copy._exponent = 1
+ }
+
+ while copy._length != 0 {
+ var remainder: UInt16 = 0
+ if copy._exponent == 0 {
+ i -= 1
+ buffer[i] = decimalChar
+ }
+ copy._exponent += 1
+ (remainder,_) = divideByShort(©, 10)
+ i -= 1
+ buffer[i] = Int8(remainder) + ZERO
+ }
+ if copy._exponent <= 0 {
+ while copy._exponent != 0 {
+ i -= 1
+ buffer[i] = ZERO
+ copy._exponent += 1
+ }
+ i -= 1
+ buffer[i] = decimalChar
+ i -= 1
+ buffer[i] = ZERO
+ }
+ if copy._isNegative != 0 {
+ i -= 1
+ buffer[i] = MINUS
+ }
+ return String(cString: Array(buffer.suffix(from:i)))
+ }
}
-public func NSDecimalIsNotANumber(_ dcm: UnsafePointer<Decimal>) -> Bool { NSUnimplemented() }
+fileprivate func divideByShort<T:VariableLengthNumber>(_ d: inout T, _ divisor:UInt16) -> (UInt16,NSDecimalNumber.CalculationError) {
+ if divisor == 0 {
+ d._length = 0
+ return (0,.divideByZero)
+ }
+ // note the below is not the same as from length to 0 by -1
+ var carry: UInt32 = 0
+ for i in (0..<d._length).reversed() {
+ let accumulator = UInt32(d[i]) + carry * (1<<16)
+ d[i] = UInt16(accumulator / UInt32(divisor))
+ carry = accumulator % UInt32(divisor)
+ }
+ d.trimTrailingZeros()
+ return (UInt16(carry),.noError)
+}
+fileprivate func multiplyByShort<T:VariableLengthNumber>(_ d: inout T, _ mul:UInt16) -> NSDecimalNumber.CalculationError {
+ if mul == 0 {
+ d._length = 0
+ return .noError
+ }
+ var carry: UInt32 = 0
+ // FIXME handle NSCalculationOverflow here?
+ for i in 0..<d._length {
+ let accumulator: UInt32 = UInt32(d[i]) * UInt32(mul) + carry
+ carry = accumulator >> 16
+ d[i] = UInt16(truncatingBitPattern: accumulator)
+ }
+ if carry != 0 {
+ if d._length >= Decimal.maxSize {
+ return .overflow
+ }
+ d[d._length] = UInt16(truncatingBitPattern: carry)
+ d._length += 1
+ }
+ return .noError
+}
+
+fileprivate func addShort<T:VariableLengthNumber>(_ d: inout T, _ add:UInt16) -> NSDecimalNumber.CalculationError {
+ var carry:UInt32 = UInt32(add)
+ for i in 0..<d._length {
+ let accumulator: UInt32 = UInt32(d[i]) + carry
+ carry = accumulator >> 16
+ d[i] = UInt16(truncatingBitPattern: accumulator)
+ }
+ if carry != 0 {
+ if d._length >= Decimal.maxSize {
+ return .overflow
+ }
+ d[d._length] = UInt16(truncatingBitPattern: carry)
+ d._length += 1
+ }
+ return .noError
+}
+
+public func NSDecimalIsNotANumber(_ dcm: UnsafePointer<Decimal>) -> Bool {
+ return dcm.pointee.isNaN
+}
/*************** Operations ***********/
-public func NSDecimalCopy(_ destination: UnsafeMutablePointer<Decimal>, _ source: UnsafePointer<Decimal>) { NSUnimplemented() }
+public func NSDecimalCopy(_ destination: UnsafeMutablePointer<Decimal>, _ source: UnsafePointer<Decimal>) {
+ destination.pointee.__lengthAndFlags = source.pointee.__lengthAndFlags
+ destination.pointee.__exponent = source.pointee.__exponent
+ destination.pointee.__reserved = source.pointee.__reserved
+ destination.pointee._mantissa = source.pointee._mantissa
+}
-public func NSDecimalCompact(_ number: UnsafeMutablePointer<Decimal>) { NSUnimplemented() }
+public func NSDecimalCompact(_ number: UnsafeMutablePointer<Decimal>) {
+ number.pointee.compact()
+}
-public func NSDecimalCompare(_ leftOperand: UnsafePointer<Decimal>, _ rightOperand: UnsafePointer<Decimal>) -> ComparisonResult { NSUnimplemented() }
// NSDecimalCompare:Compares leftOperand and rightOperand.
+public func NSDecimalCompare(_ leftOperand: UnsafePointer<Decimal>, _ rightOperand: UnsafePointer<Decimal>) -> ComparisonResult {
+ let left = leftOperand.pointee
+ let right = rightOperand.pointee
+ return left.compare(to: right)
+}
-public func NSDecimalRound(_ result: UnsafeMutablePointer<Decimal>, _ number: UnsafePointer<Decimal>, _ scale: Int, _ roundingMode: NSDecimalNumber.RoundingMode) { NSUnimplemented() }
+fileprivate extension UInt16 {
+ func compareTo(_ other: UInt16) -> ComparisonResult {
+ if self < other {
+ return .orderedAscending
+ } else if self > other {
+ return .orderedDescending
+ } else {
+ return .orderedSame
+ }
+ }
+}
+
+fileprivate func decimalCompare<T:VariableLengthNumber>(
+ _ left: T,
+ _ right: T) -> ComparisonResult {
+
+ if left._length > right._length {
+ return .orderedDescending
+ }
+ if left._length < right._length {
+ return .orderedAscending
+ }
+ let length = left._length // == right._length
+ for i in 0..<length {
+ let comparison = left[i].compareTo(right[i])
+ if comparison != .orderedSame {
+ return comparison
+ }
+ }
+ return .orderedSame
+}
+
+fileprivate func fitMantissa(_ big: inout WideDecimal, _ exponent: inout Int32, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError {
+
+ if big._length <= Decimal.maxSize {
+ return .noError
+ }
+
+ var remainder: UInt16 = 0
+ var previousRemainder: Bool = false
+
+ // Divide by 10 as much as possible
+ while big._length > Decimal.maxSize + 1 {
+ if remainder != 0 {
+ previousRemainder = true
+ }
+ (remainder,_) = divideByShort(&big,10000)
+ exponent += 4
+ }
+
+ while big._length > Decimal.maxSize {
+ if remainder != 0 {
+ previousRemainder = true
+ }
+ (remainder,_) = divideByShort(&big,10)
+ exponent += 1
+ }
+
+ // If we are on a tie, adjust with previous remainder.
+ // .50001 is equivalent to .6
+ if previousRemainder && (remainder == 0 || remainder == 5) {
+ remainder += 1
+ }
+
+ if remainder == 0 {
+ return .noError
+ }
+
+ // Round the result
+ switch roundingMode {
+ case .down:
+ break
+ case .bankers:
+ if remainder == 5 && (big[0] & 1) == 0 {
+ break
+ }
+ fallthrough
+ case .plain:
+ if remainder < 5 {
+ break
+ }
+ fallthrough
+ case .up:
+ let originalLength = big._length
+ // big._length += 1 ??
+ _ = addShort(&big,1)
+ if originalLength > big._length {
+ // the last digit is == 0. Remove it.
+ _ = divideByShort(&big, 10)
+ exponent += 1
+ }
+ }
+ return .lossOfPrecision;
+}
+
+fileprivate func integerMultiply<T:VariableLengthNumber>(_ big: inout T,
+ _ left: T,
+ _ right: Decimal) -> NSDecimalNumber.CalculationError {
+ if left._length == 0 || right._length == 0 {
+ big._length = 0
+ return .noError
+ }
+
+ if big._length == 0 || big._length > left._length + right._length {
+ big._length = min(big.maxMantissaLength,left._length + right._length)
+ }
+
+ big.zeroMantissa()
+
+ var carry: UInt16 = 0
+
+ for j in 0..<right._length {
+ var accumulator: UInt32 = 0
+ carry = 0
+
+ for i in 0..<left._length {
+ if i + j < big._length {
+ let bigij = UInt32(big[i+j])
+ accumulator = UInt32(carry) + bigij + UInt32(right[j]) * UInt32(left[i])
+ carry = UInt16(truncatingBitPattern:accumulator >> UInt32(16))
+ big[i+j] = UInt16(truncatingBitPattern:accumulator)
+ } else if carry != 0 || (right[j] == 0 && left[j] == 0) {
+ return .overflow
+ }
+ }
+
+ if carry != 0 {
+ if left._length + j < big._length {
+ big[left._length + j] = carry
+ } else {
+ return .overflow
+ }
+ }
+ }
+
+ big.trimTrailingZeros()
+
+ return .noError
+}
+
+fileprivate func integerDivide<T:VariableLengthNumber>(_ r: inout T,
+ _ cu: T,
+ _ cv: Decimal) -> NSDecimalNumber.CalculationError {
+ // Calculate result = a / b.
+ // Result could NOT be a pointer to same space as a or b.
+ // resultLen must be >= aLen - bLen.
+ //
+ // Based on algorithm in The Art of Computer Programming, Volume 2,
+ // Seminumerical Algorithms by Donald E. Knuth, 2nd Edition. In addition
+ // you need to consult the erratas for the book available at:
+ //
+ // http://www-cs-faculty.stanford.edu/~uno/taocp.html
+
+ var u = WideDecimal(true)
+ var v = WideDecimal(true) // divisor
+
+ // Simple case
+ if cv.isZero {
+ return .divideByZero;
+ }
+
+ // If u < v, the result is approximately 0...
+ if cu._length < cv._length {
+ for i in 0..<cv._length {
+ if cu[i] < cv[i] {
+ r._length = 0
+ return .noError;
+ }
+ }
+ }
+
+ // Fast algorithm
+ if cv._length == 1 {
+ r = cu
+ let (_,error) = divideByShort(&r, cv[0])
+ return error
+ }
+
+ u.copyMantissa(from: cu)
+ v.copyMantissa(from: cv)
+
+ u._length = cu._length + 1
+ v._length = cv._length + 1
+
+ // D1: Normalize
+ // Calculate d such that d*highest_digit of v >= b/2 (0x8000)
+ //
+ // I could probably use something smarter to get d to be a power of 2.
+ // In this case the multiply below became only a shift.
+ let d: UInt32 = UInt32((1 << 16) / Int(cv[cv._length - 1] + 1))
+
+ // This is to make the whole algorithm work and u*d/v*d == u/v
+ _ = multiplyByShort(&u, UInt16(d))
+ _ = multiplyByShort(&v, UInt16(d))
+
+ u.trimTrailingZeros()
+ v.trimTrailingZeros()
+
+ // Set a zero at the leftmost u position if the multiplication
+ // does not have a carry.
+ if u._length == cu._length {
+ u[u._length] = 0
+ u._length += 1
+ }
+
+ v[v._length] = 0; // Set a zero at the leftmost v position.
+ // the algorithm will use it during the
+ // multiplication/subtraction phase.
+
+ // Determine the size of the quotient.
+ // It's an approximate value.
+ let ql:UInt16 = UInt16(u._length - v._length)
+
+ // Some useful constants for the loop
+ // It's used to determine the quotient digit as fast as possible
+ // The test vl > 1 is probably useless, since optimizations
+ // up there are taking over this case. I'll keep it, just in case.
+ let v1:UInt16 = v[v._length-1]
+ let v2:UInt16 = v._length > 1 ? v[v._length-2] : 0
+
+ // D2: initialize j
+ // On each pass, build a single value for the quotient.
+ for j in 0..<ql {
+
+ // D3: calculate q^
+ // This formula and test for q gives at most q+1; See Knuth for proof.
+
+ let ul = u._length
+ let tmp:UInt32 = UInt32(u[ul - UInt32(j) - UInt32(1)]) << 16 + UInt32(u[ul - UInt32(j) - UInt32(2)])
+ var q:UInt32 = tmp / UInt32(v1) // Quotient digit. could be a short.
+ var rtmp:UInt32 = tmp % UInt32(v1)
+
+ // This test catches all cases where q is really q+2 and
+ // most where it is q+1
+ if q == (1 << 16) || UInt32(v2) * q > (rtmp<<16) + UInt32(u[ul - UInt32(j) - UInt32(3)]) {
+ q -= 1
+ rtmp += UInt32(v1)
+
+ if (rtmp < (1 << 16)) && ( (q == (1 << 16) ) || ( UInt32(v2) * q > (rtmp<<16) + UInt32(u[ul - UInt32(j) - UInt32(3)])) ) {
+ q -= 1
+ rtmp += UInt32(v1)
+ }
+ }
+
+ // D4: multiply and subtract.
+
+ var mk:UInt32 = 0 // multiply carry
+ var sk:UInt32 = 1 // subtraction carry
+ var acc:UInt32
+
+ // We perform a multiplication and a subtraction
+ // during the same pass...
+ for i in 0...v._length {
+ let ul = u._length
+ let vl = v._length
+ acc = q * UInt32(v[i]) + mk // multiply
+ mk = acc >> 16 // multiplication carry
+ acc = acc & 0xffff;
+ acc = 0xffff + UInt32(u[ul - vl + i - UInt32(j) - UInt32(1)]) - acc + sk; // subtract
+ sk = acc >> 16;
+ u[ul - vl + i - UInt32(j) - UInt32(1)] = UInt16(truncatingBitPattern:acc)
+ }
+
+ // D5: test remainder
+ // This test catches cases where q is still q + 1
+ if sk == 0 {
+ // D6: add back.
+ var k:UInt32 = 0 // Addition carry
+
+ // subtract one from the quotient digit
+ q -= 1
+ for i in 0...v._length {
+ let ul = u._length
+ let vl = v._length
+ acc = UInt32(v[i]) + UInt32(u[UInt32(ul) - UInt32(vl) + UInt32(i) - UInt32(j) - UInt32(1)]) + k
+ k = acc >> 16;
+ u[UInt32(ul) - UInt32(vl) + UInt32(i) - UInt32(j) - UInt32(1)] = UInt16(truncatingBitPattern:acc)
+ }
+ // k must be == 1 here
+ }
+
+ r[UInt32(ql - j - UInt16(1))] = UInt16(q)
+ // D7: loop on j
+ }
+
+ r._length = UInt32(ql);
+
+ r.trimTrailingZeros()
+
+ return .noError;
+}
+
+fileprivate func integerMultiplyByPowerOf10<T:VariableLengthNumber>(_ result: inout T, _ left: T, _ p: Int) -> NSDecimalNumber.CalculationError {
+ var power = p
+ if power == 0 {
+ result = left
+ return .noError
+ }
+ let isNegative = power < 0
+ if isNegative {
+ power = -power
+ }
+ result = left
+
+ let maxpow10 = pow10.count - 1
+ var error:NSDecimalNumber.CalculationError = .noError
+
+ while power > maxpow10 {
+ var big = T()
+
+ power -= maxpow10
+ let p10 = pow10[maxpow10]
+
+ if !isNegative {
+ error = integerMultiply(&big,result,p10)
+ } else {
+ error = integerDivide(&big,result,p10)
+ }
+
+ if error != .noError && error != .lossOfPrecision {
+ return error;
+ }
+
+ for i in 0..<big._length {
+ result[i] = big[i]
+ }
+
+ result._length = big._length
+ }
+
+ var big = T()
+
+ // Handle the rest of the power (<= maxpow10)
+ let p10 = pow10[Int(power)]
+
+ if !isNegative {
+ error = integerMultiply(&big, result, p10)
+ } else {
+ error = integerDivide(&big, result, p10)
+ }
+
+ for i in 0..<big._length {
+ result[i] = big[i]
+ }
+
+ result._length = big._length
+
+ return error;
+}
+
+public func NSDecimalRound(_ result: UnsafeMutablePointer<Decimal>, _ number: UnsafePointer<Decimal>, _ scale: Int, _ roundingMode: NSDecimalNumber.RoundingMode) {
+ NSDecimalCopy(result,number) // this is unnecessary if they are the same address, but we can't test that here
+ result.pointee.round(scale: scale,roundingMode: roundingMode)
+}
// Rounds num to the given scale using the given mode.
// result may be a pointer to same space as num.
// scale indicates number of significant digits after the decimal point
-public func NSDecimalNormalize(_ number1: UnsafeMutablePointer<Decimal>, _ number2: UnsafeMutablePointer<Decimal>, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError { NSUnimplemented() }
+public func NSDecimalNormalize(_ a: UnsafeMutablePointer<Decimal>, _ b: UnsafeMutablePointer<Decimal>, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError {
+ var diffexp = a.pointee.__exponent - b.pointee.__exponent
+ var result = Decimal()
-public func NSDecimalAdd(_ result: UnsafeMutablePointer<Decimal>, _ leftOperand: UnsafePointer<Decimal>, _ rightOperand: UnsafePointer<Decimal>, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError { NSUnimplemented() }
+ //
+ // If the two numbers share the same exponents,
+ // the normalisation is already done
+ //
+ if diffexp == 0 {
+ return .noError
+ }
+
+ //
+ // Put the smallest of the two in aa
+ //
+ var aa: UnsafeMutablePointer<Decimal>
+ var bb: UnsafeMutablePointer<Decimal>
+
+ if diffexp < 0 {
+ aa = b
+ bb = a
+ diffexp = -diffexp
+ } else {
+ aa = a
+ bb = b
+ }
+
+ //
+ // Build a backup for aa
+ //
+ var backup = Decimal()
+
+ NSDecimalCopy(&backup,aa)
+
+ //
+ // Try to multiply aa to reach the same exponent level than bb
+ //
+
+ if integerMultiplyByPowerOf10(&result, aa.pointee, Int(diffexp)) == .noError {
+ // Succeed. Adjust the length/exponent info
+ // and return no errorNSDecimalNormalize
+ aa.pointee.copyMantissa(from: result)
+ aa.pointee._exponent = bb.pointee._exponent
+ return .noError;
+ }
+
+ //
+ // Failed, restart from scratch
+ //
+ NSDecimalCopy(aa, &backup);
+
+ //
+ // What is the maximum pow10 we can apply to aa ?
+ //
+ let logBase10of2to16 = 4.81647993
+ let aaLength = aa.pointee._length
+ let maxpow10 = Int8(floor(Double(Decimal.maxSize - aaLength) * logBase10of2to16))
+
+ //
+ // Divide bb by this value
+ //
+ _ = integerMultiplyByPowerOf10(&result, bb.pointee, maxpow10 - diffexp)
+
+ bb.pointee.copyMantissa(from: result)
+ bb.pointee._exponent -= maxpow10 - diffexp;
+
+ //
+ // If bb > 0 multiply aa by the same value
+ //
+ if !bb.pointee.isZero {
+ _ = integerMultiplyByPowerOf10(&result, aa.pointee, Int(maxpow10))
+ aa.pointee.copyMantissa(from: result)
+ aa.pointee._exponent -= Int32(maxpow10)
+ } else {
+ bb.pointee._exponent = aa.pointee._exponent;
+ }
+
+ //
+ // the two exponents are now identical, but we've lost some digits in the operation.
+ //
+ return .lossOfPrecision;
+}
+
+public func NSDecimalAdd(_ result: UnsafeMutablePointer<Decimal>, _ leftOperand: UnsafePointer<Decimal>, _ rightOperand: UnsafePointer<Decimal>, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError {
+ if leftOperand.pointee.isNaN || rightOperand.pointee.isNaN {
+ result.pointee.setNaN()
+ return .overflow
+ }
+ if leftOperand.pointee.isZero {
+ NSDecimalCopy(result, rightOperand)
+ return .noError
+ } else if rightOperand.pointee.isZero {
+ NSDecimalCopy(result, leftOperand)
+ return .noError
+ } else {
+ var a = Decimal()
+ var b = Decimal()
+ var error:NSDecimalNumber.CalculationError = .noError
+
+ NSDecimalCopy(&a,leftOperand)
+ NSDecimalCopy(&b,rightOperand)
+
+ let normalizeError = NSDecimalNormalize(&a, &b,roundingMode)
+
+ if a.isZero {
+ NSDecimalCopy(result,&b)
+ return normalizeError
+ }
+ if b.isZero {
+ NSDecimalCopy(result,&a)
+ return normalizeError
+ }
+
+ result.pointee._exponent = a._exponent
+
+ if a.isNegative == b.isNegative {
+ var big = WideDecimal()
+ result.pointee.isNegative = a.isNegative
+
+ // No possible error here.
+ _ = integerAdd(&big,&a,&b)
+
+ if big._length > Decimal.maxSize {
+ var exponent:Int32 = 0
+ error = fitMantissa(&big, &exponent, roundingMode)
+
+ let newExponent = result.pointee._exponent + exponent
+
+ // Just to be sure!
+ if newExponent > Int32(Int8.max) {
+ result.pointee.setNaN()
+ return .overflow
+ }
+ result.pointee._exponent = newExponent
+ }
+ let length = min(Decimal.maxSize,big._length)
+ for i in 0..<length {
+ result.pointee[i] = big[i]
+ }
+ result.pointee._length = length
+ } else { // not the same sign
+ let comparison = decimalCompare(a,b)
+
+ switch comparison {
+ case .orderedSame:
+ result.pointee.setZero()
+ case .orderedAscending:
+ _ = integerSubtract(&result.pointee,&b,&a)
+ result.pointee.isNegative = b.isNegative
+ case .orderedDescending:
+ _ = integerSubtract(&result.pointee,&a,&b)
+ result.pointee.isNegative = a.isNegative
+ }
+ }
+ result.pointee._isCompact = 0
+ NSDecimalCompact(result)
+ return error == .noError ? normalizeError : error
+ }
+}
+
+fileprivate func integerAdd(_ result: inout WideDecimal, _ left: inout Decimal, _ right: inout Decimal) -> NSDecimalNumber.CalculationError {
+ var i:UInt32 = 0
+ var carry:UInt16 = 0
+ var accumulator:UInt32 = 0
+
+ let c:UInt32 = min(left._length, right._length)
+
+ while i < c {
+ let li = UInt32(left[i])
+ let ri = UInt32(right[i])
+ accumulator = li + ri + UInt32(carry)
+ carry = UInt16(truncatingBitPattern:accumulator >> 16)
+ result[i] = UInt16(truncatingBitPattern:accumulator)
+ i += 1
+ }
+
+ while i < left._length {
+ if carry != 0 {
+ let li = UInt32(left[i])
+ accumulator = li + UInt32(carry)
+ carry = UInt16(truncatingBitPattern:accumulator >> 16)
+ result[i] = UInt16(truncatingBitPattern:accumulator)
+ i += 1
+ } else {
+ while i < left._length {
+ result[i] = left[i]
+ i += 1
+ }
+ break
+ }
+ }
+ while i < right._length {
+ if carry != 0 {
+ let ri = UInt32(right[i])
+ accumulator = ri + UInt32(carry)
+ carry = UInt16(truncatingBitPattern:accumulator >> 16)
+ result[i] = UInt16(truncatingBitPattern:accumulator)
+ i += 1
+ } else {
+ while i < right._length {
+ result[i] = right[i]
+ i += 1
+ }
+ break
+ }
+ }
+
+ if carry != 0 {
+ if result._length < i {
+ result._length = i
+ return .overflow
+ } else {
+ result[i] = carry
+ i += 1
+ }
+ }
+ result._length = i;
+ return .noError;
+}
+
+// integerSubtract: Subtract b from a, put the result in result, and
+// modify resultLen to match the length of the result.
+// Result may be a pointer to same space as a or b.
+// resultLen must be >= Max(aLen,bLen).
+// Could return NSCalculationOverflow if b > a. In this case 0 - result
+// give b-a...
+//
+fileprivate func integerSubtract(_ result: inout Decimal, _ left: inout Decimal, _ right: inout Decimal) -> NSDecimalNumber.CalculationError {
+ var i:UInt32 = 0
+ var carry:UInt16 = 1
+ var accumulator:UInt32 = 0
+
+ let c:UInt32 = min(left._length, right._length)
+
+ while i < c {
+ let li = UInt32(left[i])
+ let ri = UInt32(right[i])
+ accumulator = 0xffff + li - ri + UInt32(carry)
+ carry = UInt16(truncatingBitPattern:accumulator >> 16)
+ result[i] = UInt16(truncatingBitPattern:accumulator)
+ i += 1
+ }
+
+ while i < left._length {
+ if carry != 0 {
+ let li = UInt32(left[i])
+ accumulator = 0xffff + li // + no carry
+ carry = UInt16(truncatingBitPattern:accumulator >> 16)
+ result[i] = UInt16(truncatingBitPattern:accumulator)
+ i += 1
+ } else {
+ while i < left._length {
+ result[i] = left[i]
+ i += 1
+ }
+ break
+ }
+ }
+ while i < right._length {
+ let ri = UInt32(right[i])
+ accumulator = 0xffff - ri + UInt32(carry)
+ carry = UInt16(truncatingBitPattern:accumulator >> 16)
+ result[i] = UInt16(truncatingBitPattern:accumulator)
+ i += 1
+ }
+
+ if carry != 0 {
+ return .overflow
+ }
+ result._length = i;
+
+ result.trimTrailingZeros()
+
+ return .noError;
+}
+
// Exact operations. result may be a pointer to same space as leftOperand or rightOperand
-public func NSDecimalSubtract(_ result: UnsafeMutablePointer<Decimal>, _ leftOperand: UnsafePointer<Decimal>, _ rightOperand: UnsafePointer<Decimal>, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError { NSUnimplemented() }
+public func NSDecimalSubtract(_ result: UnsafeMutablePointer<Decimal>, _ leftOperand: UnsafePointer<Decimal>, _ rightOperand: UnsafePointer<Decimal>, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError {
+ var r = rightOperand.pointee
+ if r._length != 0 {
+ r.negate()
+ }
+ return NSDecimalAdd(result, leftOperand, &r, roundingMode)
+}
// Exact operations. result may be a pointer to same space as leftOperand or rightOperand
-public func NSDecimalMultiply(_ result: UnsafeMutablePointer<Decimal>, _ leftOperand: UnsafePointer<Decimal>, _ rightOperand: UnsafePointer<Decimal>, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError { NSUnimplemented() }
+public func NSDecimalMultiply(_ result: UnsafeMutablePointer<Decimal>, _ leftOperand: UnsafePointer<Decimal>, _ rightOperand: UnsafePointer<Decimal>, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError {
+
+ if leftOperand.pointee.isNaN || rightOperand.pointee.isNaN {
+ result.pointee.setNaN()
+ return .overflow
+ }
+ if leftOperand.pointee.isZero || rightOperand.pointee.isZero {
+ result.pointee.setZero()
+ return .noError
+ }
+
+ var big = WideDecimal()
+ var calculationError:NSDecimalNumber.CalculationError = .noError
+
+ calculationError = integerMultiply(&big,WideDecimal(leftOperand.pointee),rightOperand.pointee)
+
+ result.pointee._isNegative = (leftOperand.pointee._isNegative + rightOperand.pointee._isNegative) % 2
+
+ var newExponent = leftOperand.pointee._exponent + rightOperand.pointee._exponent
+
+ if big._length > Decimal.maxSize {
+ var exponent:Int32 = 0
+ calculationError = fitMantissa(&big, &exponent, roundingMode)
+ newExponent += exponent
+ }
+
+ for i in 0..<big._length {
+ result.pointee[i] = big[i]
+ }
+ result.pointee._length = big._length
+ result.pointee._isCompact = 0
+
+ if newExponent > Int32(Int8.max) {
+ result.pointee.setNaN()
+ return .overflow
+ }
+ result.pointee._exponent = newExponent
+ NSDecimalCompact(result)
+ return calculationError
+}
// Exact operations. result may be a pointer to same space as leftOperand or rightOperand
-public func NSDecimalDivide(_ result: UnsafeMutablePointer<Decimal>, _ leftOperand: UnsafePointer<Decimal>, _ rightOperand: UnsafePointer<Decimal>, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError { NSUnimplemented() }
+public func NSDecimalDivide(_ result: UnsafeMutablePointer<Decimal>, _ leftOperand: UnsafePointer<Decimal>, _ rightOperand: UnsafePointer<Decimal>, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError {
+
+ if leftOperand.pointee.isNaN || rightOperand.pointee.isNaN {
+ result.pointee.setNaN()
+ return .overflow
+ }
+ if rightOperand.pointee.isZero {
+ result.pointee.setNaN()
+ return .divideByZero
+ }
+ if leftOperand.pointee.isZero {
+ result.pointee.setZero()
+ return .noError
+ }
+ var a = Decimal()
+ var b = Decimal()
+ var big = WideDecimal()
+ var exponent:Int32 = 0
+
+ NSDecimalCopy(&a, leftOperand)
+ NSDecimalCopy(&b, rightOperand)
+
+ /* If the precision of the left operand is much smaller
+ * than that of the right operand (for example,
+ * 20 and 0.112314123094856724234234572), then the
+ * difference in their exponents is large and a lot of
+ * precision will be lost below. This is particularly
+ * true as the difference approaches 38 or larger.
+ * Normalizing here looses some precision on the
+ * individual operands, but often produces a more
+ * accurate result later. I chose 19 arbitrarily
+ * as half of the magic 38, so that normalization
+ * doesn't always occur. */
+ if (19 <= a._exponent - b._exponent) {
+ _ = NSDecimalNormalize(&a, &b, roundingMode);
+ /* We ignore the small loss of precision this may
+ * induce in the individual operands. */
+
+ /* Sometimes the normalization done previously is inappropriate and
+ * forces one of the operands to 0. If this happens, restore both. */
+ if a.isZero || b.isZero {
+ NSDecimalCopy(&a, leftOperand);
+ NSDecimalCopy(&b, rightOperand);
+ }
+ }
+
+ _ = integerMultiplyByPowerOf10(&big, WideDecimal(a), 38) // Trust me, it's 38 !
+ _ = integerDivide(&big, big, b)
+ _ = fitMantissa(&big, &exponent, .down)
+
+ let length = min(big._length,Decimal.maxSize)
+ for i in 0..<length {
+ result.pointee[i] = big[i]
+ }
+
+ result.pointee._length = length
+
+ result.pointee.isNegative = a._isNegative != b._isNegative
+
+ exponent = a._exponent - b._exponent - 38 + exponent
+ if exponent < Int32(Int8.min) {
+ result.pointee.setNaN()
+ return .underflow
+ }
+ if exponent > Int32(Int8.max) {
+ result.pointee.setNaN()
+ return .overflow;
+ }
+ result.pointee._exponent = Int32(exponent)
+ result.pointee._isCompact = 0
+ NSDecimalCompact(result)
+ return .noError
+}
// Division could be silently inexact;
// Exact operations. result may be a pointer to same space as leftOperand or rightOperand
-public func NSDecimalPower(_ result: UnsafeMutablePointer<Decimal>, _ number: UnsafePointer<Decimal>, _ power: Int, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError { NSUnimplemented() }
+public func NSDecimalPower(_ result: UnsafeMutablePointer<Decimal>, _ number: UnsafePointer<Decimal>, _ power: Int, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError {
-public func NSDecimalMultiplyByPowerOf10(_ result: UnsafeMutablePointer<Decimal>, _ number: UnsafePointer<Decimal>, _ power: Int16, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError { NSUnimplemented() }
+ if number.pointee.isNaN {
+ result.pointee.setNaN()
+ return .overflow
+ }
+ NSDecimalCopy(result,number)
+ return result.pointee.power(UInt(power), roundingMode:roundingMode)
+}
-public func NSDecimalString(_ dcm: UnsafePointer<Decimal>, _ locale: AnyObject?) -> String { NSUnimplemented() }
+public func NSDecimalMultiplyByPowerOf10(_ result: UnsafeMutablePointer<Decimal>, _ number: UnsafePointer<Decimal>, _ power: Int16, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError {
+ NSDecimalCopy(result,number)
+ return result.pointee.multiply(byPowerOf10: power)
+}
+
+public func NSDecimalString(_ dcm: UnsafePointer<Decimal>, _ locale: AnyObject?) -> String {
+ guard locale == nil else {
+ fatalError("Locale not supported: \(locale!)")
+ }
+ return dcm.pointee.description
+}
+
+fileprivate protocol VariableLengthNumber {
+ var _length: UInt32 { get set }
+ init()
+ subscript(index:UInt32) -> UInt16 { get set }
+ var isZero:Bool { get }
+ mutating func copyMantissa<T:VariableLengthNumber>(from other:T)
+ mutating func zeroMantissa()
+ mutating func trimTrailingZeros()
+ var maxMantissaLength: UInt32 { get }
+}
+
+extension Decimal: VariableLengthNumber {
+ var maxMantissaLength:UInt32 {
+ return Decimal.maxSize
+ }
+ fileprivate mutating func zeroMantissa() {
+ for i in 0..<Decimal.maxSize {
+ self[i] = 0
+ }
+ }
+ internal mutating func trimTrailingZeros() {
+ if _length > Decimal.maxSize {
+ _length = Decimal.maxSize
+ }
+ while _length != 0 && self[_length - 1] == 0 {
+ _length -= 1
+ }
+ }
+ fileprivate mutating func copyMantissa<T : VariableLengthNumber>(from other: T) {
+ if other._length > maxMantissaLength {
+ for i in maxMantissaLength..<other._length {
+ guard other[i] == 0 else {
+ fatalError("Loss of precision during copy other[\(i)] \(other[i]) != 0")
+ }
+ }
+ }
+ let length = min(other._length, maxMantissaLength)
+ for i in 0..<length {
+ self[i] = other[i]
+ }
+ self._length = length
+ self._isCompact = 0
+ }
+}
+
+// Provides a way with dealing with extra-length decimals, used for calculations
+fileprivate struct WideDecimal : VariableLengthNumber {
+ var maxMantissaLength:UInt32 {
+ return _extraWide ? 17 : 16
+ }
+
+ fileprivate mutating func zeroMantissa() {
+ for i in 0..<maxMantissaLength {
+ self[i] = 0
+ }
+ }
+ fileprivate mutating func trimTrailingZeros() {
+ while _length != 0 && self[_length - 1] == 0 {
+ _length -= 1
+ }
+ }
+ init() {
+ self.init(false)
+ }
+
+ fileprivate mutating func copyMantissa<T : VariableLengthNumber>(from other: T) {
+ let length = other is Decimal ? min(other._length,Decimal.maxSize) : other._length
+ for i in 0..<length {
+ self[i] = other[i]
+ }
+ self._length = length
+ }
+
+ var isZero: Bool {
+ return _length == 0
+ }
+
+ var __length: UInt16
+ var _mantissa: (UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16,
+ UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16)
+ // Most uses of this class use 16 shorts, but integer division uses 17 shorts
+ var _extraWide: Bool
+ var _length: UInt32 {
+ get {
+ return UInt32(__length)
+ }
+ set {
+ guard newValue <= maxMantissaLength else {
+ fatalError("Attempt to set a length greater than capacity \(newValue) > \(maxMantissaLength)")
+ }
+ __length = UInt16(newValue)
+ }
+ }
+ init(_ extraWide:Bool = false) {
+ __length = 0
+ _mantissa = (UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0))
+ _extraWide = extraWide
+ }
+ init(_ decimal:Decimal) {
+ self.__length = UInt16(decimal._length)
+ self._extraWide = false
+ self._mantissa = (decimal[0],decimal[1],decimal[2],decimal[3],decimal[4],decimal[5],decimal[6],decimal[7],UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0))
+ }
+ subscript(index:UInt32) -> UInt16 {
+ get {
+ switch index {
+ case 0: return _mantissa.0
+ case 1: return _mantissa.1
+ case 2: return _mantissa.2
+ case 3: return _mantissa.3
+ case 4: return _mantissa.4
+ case 5: return _mantissa.5
+ case 6: return _mantissa.6
+ case 7: return _mantissa.7
+ case 8: return _mantissa.8
+ case 9: return _mantissa.9
+ case 10: return _mantissa.10
+ case 11: return _mantissa.11
+ case 12: return _mantissa.12
+ case 13: return _mantissa.13
+ case 14: return _mantissa.14
+ case 15: return _mantissa.15
+ case 16 where _extraWide: return _mantissa.16 // used in integerDivide
+ default: fatalError("Invalid index \(index) for _mantissa")
+ }
+ }
+ set {
+ switch index {
+ case 0: _mantissa.0 = newValue
+ case 1: _mantissa.1 = newValue
+ case 2: _mantissa.2 = newValue
+ case 3: _mantissa.3 = newValue
+ case 4: _mantissa.4 = newValue
+ case 5: _mantissa.5 = newValue
+ case 6: _mantissa.6 = newValue
+ case 7: _mantissa.7 = newValue
+ case 8: _mantissa.8 = newValue
+ case 9: _mantissa.9 = newValue
+ case 10: _mantissa.10 = newValue
+ case 11: _mantissa.11 = newValue
+ case 12: _mantissa.12 = newValue
+ case 13: _mantissa.13 = newValue
+ case 14: _mantissa.14 = newValue
+ case 15: _mantissa.15 = newValue
+ case 16 where _extraWide: _mantissa.16 = newValue
+ default: fatalError("Invalid index \(index) for _mantissa")
+ }
+ }
+ }
+ func toDecimal() -> Decimal {
+ var result = Decimal()
+ result._length = self._length
+ for i in 0..<_length {
+ result[i] = self[i]
+ }
+ return result
+ }
+}
+
+// == Internal (Swifty) functions ==
+
+extension Decimal {
+ fileprivate var isCompact: Bool {
+ get {
+ return _isCompact != 0
+ }
+ set {
+ _isCompact = newValue ? 1 : 0
+ }
+ }
+ fileprivate var isNegative: Bool {
+ get {
+ return _isNegative != 0
+ }
+ set {
+ _isNegative = newValue ? 1 : 0
+ }
+ }
+ fileprivate mutating func compact() {
+ if isCompact || isNaN || _length == 0 {
+ return
+ }
+ var newExponent = self._exponent
+ var remainder: UInt16 = 0
+ // Divide by 10 as much as possible
+ repeat {
+ (remainder,_) = divideByShort(&self,10)
+ newExponent += 1
+ } while remainder == 0
+ // Put the non-empty remainder in place
+ _ = multiplyByShort(&self,10)
+ _ = addShort(&self,remainder)
+ newExponent -= 1
+ // Set the new exponent
+ while newExponent > Int32(Int8.max) {
+ _ = multiplyByShort(&self,10)
+ newExponent -= 1
+ }
+ _exponent = newExponent
+ isCompact = true
+ }
+ fileprivate mutating func round(scale:Int, roundingMode:RoundingMode) {
+ // scale is the number of digits after the decimal point
+ var s = scale + _exponent
+ if s == NSDecimalNoScale || s >= 0 {
+ return
+ }
+ s = -s
+ var remainder: UInt16 = 0
+ var previousRemainder = false
+
+ let negative = _isNegative != 0
+ var newExponent = _exponent + s
+ while s > 4 {
+ if remainder != 0 {
+ previousRemainder = true
+ }
+ (remainder,_) = divideByShort(&self, 10000)
+ s -= 4
+ }
+ while s > 0 {
+ if remainder != 0 {
+ previousRemainder = true
+ }
+ (remainder,_) = divideByShort(&self, 10)
+ s -= 1
+ }
+ // If we are on a tie, adjust with premdr. .50001 is equivalent to .6
+ if previousRemainder && (remainder == 0 || remainder == 5) {
+ remainder += 1;
+ }
+ if remainder != 0 {
+ if negative {
+ switch roundingMode {
+ case .up:
+ break
+ case .bankers:
+ if remainder == 5 && (self[0] & 1) == 0 {
+ remainder += 1
+ }
+ fallthrough
+ case .plain:
+ if remainder < 5 {
+ break
+ }
+ fallthrough
+ case .down:
+ _ = addShort(&self, 1)
+ }
+ if _length == 0 {
+ _isNegative = 0;
+ }
+ } else {
+ switch roundingMode {
+ case .down:
+ break
+ case .bankers:
+ if remainder == 5 && (self[0] & 1) == 0 {
+ remainder -= 1
+ }
+ fallthrough
+ case .plain:
+ if remainder < 5 {
+ break
+ }
+ fallthrough
+ case .up:
+ _ = addShort(&self, 1)
+ }
+ }
+ }
+ _isCompact = 0;
+
+ while newExponent > Int32(Int8.max) {
+ newExponent -= 1;
+ _ = multiplyByShort(&self, 10);
+ }
+ _exponent = newExponent;
+ self.compact();
+ }
+ internal func compare(to other:Decimal) -> ComparisonResult {
+ // NaN is a special case and is arbitrary ordered before everything else
+ // Conceptually comparing with NaN is bogus anyway but raising or
+ // always returning the same answer will confuse the sorting algorithms
+ if self.isNaN {
+ return other.isNaN ? .orderedSame : .orderedAscending
+ }
+ if other.isNaN {
+ return .orderedDescending
+ }
+ // Check the sign
+ if self._isNegative > other._isNegative {
+ return .orderedAscending
+ }
+ if self._isNegative < other._isNegative {
+ return .orderedDescending
+ }
+ // If one of the two is == 0, the other is bigger
+ // because 0 implies isNegative = 0...
+ if self.isZero && other.isZero {
+ return .orderedSame
+ }
+ if self.isZero {
+ return .orderedAscending
+ }
+ if other.isZero {
+ return .orderedDescending
+ }
+ var selfNormal = self
+ var otherNormal = other
+ _ = NSDecimalNormalize(&selfNormal, &otherNormal, .down)
+ let comparison = decimalCompare(selfNormal,otherNormal)
+ if selfNormal._isNegative == 1 {
+ if comparison == .orderedDescending {
+ return .orderedAscending
+ } else if comparison == .orderedAscending {
+ return .orderedDescending
+ } else {
+ return .orderedSame
+ }
+ }
+ return comparison
+ }
+ fileprivate subscript(index:UInt32) -> UInt16 {
+ get {
+ switch index {
+ case 0: return _mantissa.0
+ case 1: return _mantissa.1
+ case 2: return _mantissa.2
+ case 3: return _mantissa.3
+ case 4: return _mantissa.4
+ case 5: return _mantissa.5
+ case 6: return _mantissa.6
+ case 7: return _mantissa.7
+ default: fatalError("Invalid index \(index) for _mantissa")
+ }
+ }
+ set {
+ switch index {
+ case 0: _mantissa.0 = newValue
+ case 1: _mantissa.1 = newValue
+ case 2: _mantissa.2 = newValue
+ case 3: _mantissa.3 = newValue
+ case 4: _mantissa.4 = newValue
+ case 5: _mantissa.5 = newValue
+ case 6: _mantissa.6 = newValue
+ case 7: _mantissa.7 = newValue
+ default: fatalError("Invalid index \(index) for _mantissa")
+ }
+ }
+ }
+ fileprivate mutating func setNaN() {
+ _length = 0
+ _isNegative = 1
+ }
+ fileprivate mutating func setZero() {
+ _length = 0
+ _isNegative = 0
+ }
+ fileprivate mutating func multiply(byPowerOf10 power:Int16) -> CalculationError {
+ if isNaN {
+ return .overflow
+ }
+ if isZero {
+ return .noError
+ }
+ let newExponent = _exponent + Int32(power)
+ if newExponent < Int32(Int8.min) {
+ setNaN()
+ return .underflow
+ }
+ if newExponent > Int32(Int8.max) {
+ setNaN()
+ return .overflow
+ }
+ _exponent = newExponent
+ return .noError
+ }
+ fileprivate mutating func power(_ p:UInt, roundingMode:RoundingMode) -> CalculationError {
+ if isNaN {
+ return .overflow
+ }
+ var power = p
+ if power == 0 {
+ _exponent = 0
+ _length = 1
+ _isNegative = 0
+ self[0] = 1
+ _isCompact = 1
+ return .noError
+ } else if power == 1 {
+ return .noError
+ }
+
+ var temporary = Decimal(1)
+ var error:CalculationError = .noError
+
+ while power > 1 {
+ if power % 2 == 1 {
+ let previousError = error
+ error = NSDecimalMultiply(&temporary,&temporary,&self,roundingMode)
+
+ if previousError != .noError { // FIXME is this the intent?
+ error = previousError
+ }
+
+ if error == .overflow || error == .underflow {
+ setNaN()
+ return error
+ }
+ power -= 1
+ }
+ if power != 0 {
+ let previousError = error
+ error = NSDecimalMultiply(&self,&self,&self,roundingMode)
+
+ if previousError != .noError { // FIXME is this the intent?
+ error = previousError
+ }
+
+ if error == .overflow || error == .underflow {
+ setNaN()
+ return error
+ }
+ power /= 2
+ }
+ }
+ let previousError = error
+
+ error = NSDecimalMultiply(&self, &temporary, &self, roundingMode)
+
+ if previousError != .noError { // FIXME is this the intent?
+ error = previousError
+ }
+
+ if error == .overflow || error == .underflow {
+ setNaN()
+ return error
+ }
+
+ return error
+ }
+}
+
+fileprivate let pow10 = [
+/*^00*/ Decimal(length: 1, mantissa:( 0x0001,0,0,0,0,0,0,0)),
+/*^01*/ Decimal(length: 1, mantissa:( 0x000a,0,0,0,0,0,0,0)),
+/*^02*/ Decimal(length: 1, mantissa:( 0x0064,0,0,0,0,0,0,0)),
+/*^03*/ Decimal(length: 1, mantissa:( 0x03e8,0,0,0,0,0,0,0)),
+/*^04*/ Decimal(length: 1, mantissa:( 0x2710,0,0,0,0,0,0,0)),
+/*^05*/ Decimal(length: 2, mantissa:( 0x86a0, 0x0001,0,0,0,0,0,0)),
+/*^06*/ Decimal(length: 2, mantissa:( 0x4240, 0x000f,0,0,0,0,0,0)),
+/*^07*/ Decimal(length: 2, mantissa:( 0x9680, 0x0098,0,0,0,0,0,0)),
+/*^08*/ Decimal(length: 2, mantissa:( 0xe100, 0x05f5,0,0,0,0,0,0)),
+/*^09*/ Decimal(length: 2, mantissa:( 0xca00, 0x3b9a,0,0,0,0,0,0)),
+/*^10*/ Decimal(length: 3, mantissa:( 0xe400, 0x540b, 0x0002,0,0,0,0,0)),
+/*^11*/ Decimal(length: 3, mantissa:( 0xe800, 0x4876, 0x0017,0,0,0,0,0)),
+/*^12*/ Decimal(length: 3, mantissa:( 0x1000, 0xd4a5, 0x00e8,0,0,0,0,0)),
+/*^13*/ Decimal(length: 3, mantissa:( 0xa000, 0x4e72, 0x0918,0,0,0,0,0)),
+/*^14*/ Decimal(length: 3, mantissa:( 0x4000, 0x107a, 0x5af3,0,0,0,0,0)),
+/*^15*/ Decimal(length: 4, mantissa:( 0x8000, 0xa4c6, 0x8d7e, 0x0003,0,0,0,0)),
+/*^16*/ Decimal(length: 4, mantissa:( 0x0000, 0x6fc1, 0x86f2, 0x0023,0,0,0,0)),
+/*^17*/ Decimal(length: 4, mantissa:( 0x0000, 0x5d8a, 0x4578, 0x0163,0,0,0,0)),
+/*^18*/ Decimal(length: 4, mantissa:( 0x0000, 0xa764, 0xb6b3, 0x0de0,0,0,0,0)),
+/*^19*/ Decimal(length: 4, mantissa:( 0x0000, 0x89e8, 0x2304, 0x8ac7,0,0,0,0)),
+/*^20*/ Decimal(length: 5, mantissa:( 0x0000, 0x6310, 0x5e2d, 0x6bc7, 0x0005,0,0,0)),
+/*^21*/ Decimal(length: 5, mantissa:( 0x0000, 0xdea0, 0xadc5, 0x35c9, 0x0036,0,0,0)),
+/*^22*/ Decimal(length: 5, mantissa:( 0x0000, 0xb240, 0xc9ba, 0x19e0, 0x021e,0,0,0)),
+/*^23*/ Decimal(length: 5, mantissa:( 0x0000, 0xf680, 0xe14a, 0x02c7, 0x152d,0,0,0)),
+/*^24*/ Decimal(length: 5, mantissa:( 0x0000, 0xa100, 0xcced, 0x1bce, 0xd3c2,0,0,0)),
+/*^25*/ Decimal(length: 6, mantissa:( 0x0000, 0x4a00, 0x0148, 0x1614, 0x4595, 0x0008,0,0)),
+/*^26*/ Decimal(length: 6, mantissa:( 0x0000, 0xe400, 0x0cd2, 0xdcc8, 0xb7d2, 0x0052,0,0)),
+/*^27*/ Decimal(length: 6, mantissa:( 0x0000, 0xe800, 0x803c, 0x9fd0, 0x2e3c, 0x033b,0,0)),
+/*^28*/ Decimal(length: 6, mantissa:( 0x0000, 0x1000, 0x0261, 0x3e25, 0xce5e, 0x204f,0,0)),
+/*^29*/ Decimal(length: 7, mantissa:( 0x0000, 0xa000, 0x17ca, 0x6d72, 0x0fae, 0x431e, 0x0001,0)),
+/*^30*/ Decimal(length: 7, mantissa:( 0x0000, 0x4000, 0xedea, 0x4674, 0x9cd0, 0x9f2c, 0x000c,0)),
+/*^31*/ Decimal(length: 7, mantissa:( 0x0000, 0x8000, 0x4b26, 0xc091, 0x2022, 0x37be, 0x007e,0)),
+/*^32*/ Decimal(length: 7, mantissa:( 0x0000, 0x0000, 0xef81, 0x85ac, 0x415b, 0x2d6d, 0x04ee,0)),
+/*^33*/ Decimal(length: 7, mantissa:( 0x0000, 0x0000, 0x5b0a, 0x38c1, 0x8d93, 0xc644, 0x314d,0)),
+/*^34*/ Decimal(length: 8, mantissa:( 0x0000, 0x0000, 0x8e64, 0x378d, 0x87c0, 0xbead, 0xed09, 0x0001)),
+/*^35*/ Decimal(length: 8, mantissa:( 0x0000, 0x0000, 0x8fe8, 0x2b87, 0x4d82, 0x72c7, 0x4261, 0x0013)),
+/*^36*/ Decimal(length: 8, mantissa:( 0x0000, 0x0000, 0x9f10, 0xb34b, 0x0715, 0x7bc9, 0x97ce, 0x00c0)),
+/*^37*/ Decimal(length: 8, mantissa:( 0x0000, 0x0000, 0x36a0, 0x00f4, 0x46d9, 0xd5da, 0xee10, 0x0785)),
+/*^38*/ Decimal(length: 8, mantissa:( 0x0000, 0x0000, 0x2240, 0x098a, 0xc47a, 0x5a86, 0x4ca8, 0x4b3b))
+/*^39 is on 9 shorts. */
+]
diff --git a/Foundation/NSDecimalNumber.swift b/Foundation/NSDecimalNumber.swift
index 759dc28..46b9b20 100644
--- a/Foundation/NSDecimalNumber.swift
+++ b/Foundation/NSDecimalNumber.swift
@@ -75,29 +75,86 @@
// Receiver can raise, return a new value, or return nil to ignore the exception.
+fileprivate func handle(_ error: NSDecimalNumber.CalculationError, _ handler: NSDecimalNumberBehaviors) {
+ // handle the error condition, such as throwing an error for over/underflow
+}
/*************** NSDecimalNumber: the class ***********/
open class NSDecimalNumber : NSNumber {
-
- public convenience init(mantissa: UInt64, exponent: Int16, isNegative flag: Bool) { NSUnimplemented() }
- public init(decimal dcm: Decimal) { NSUnimplemented() }
- public convenience init(string numberValue: String?) { NSUnimplemented() }
- public convenience init(string numberValue: String?, locale: AnyObject?) { NSUnimplemented() }
- public required init?(coder aDecoder: NSCoder) {
- NSUnimplemented()
+ fileprivate let decimal: Decimal
+ public convenience init(mantissa: UInt64, exponent: Int16, isNegative: Bool) {
+ var d = Decimal()
+ d._exponent = Int32(exponent)
+ d._isNegative = isNegative ? 1 : 0
+ var man = mantissa
+ d._mantissa.0 = UInt16(man & 0xffff)
+ man >>= 4
+ d._mantissa.1 = UInt16(man & 0xffff)
+ man >>= 4
+ d._mantissa.2 = UInt16(man & 0xffff)
+ man >>= 4
+ d._mantissa.3 = UInt16(man & 0xffff)
+ d._length = 4
+ d.trimTrailingZeros()
+ // TODO more parts of the mantissa...
+ self.init(decimal: d)
+ }
+ public init(decimal dcm: Decimal) {
+ self.decimal = dcm
+ super.init()
+ }
+ public convenience init(string numberValue: String?) {
+ self.init(decimal: Decimal(string: numberValue ?? "") ?? Decimal.nan)
+ }
+ public convenience init(string numberValue: String?, locale: AnyObject?) {
+ self.init(decimal: Decimal(string: numberValue ?? "", locale: locale as? Locale) ?? Decimal.nan)
+ }
+
+ public required init?(coder: NSCoder) {
+ guard coder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+ let exponent:Int32 = coder.decodeInt32(forKey: "NS.exponent")
+ let length:UInt32 = UInt32(coder.decodeInt32(forKey: "NS.length"))
+ let isNegative:UInt32 = UInt32(coder.decodeBool(forKey: "NS.negative") ? 1 : 0)
+ let isCompact:UInt32 = UInt32(coder.decodeBool(forKey: "NS.compact") ? 1 : 0)
+ // let byteOrder:UInt32 = UInt32(coder.decodeInt32(forKey: "NS.bo"))
+ guard let mantissaData: Data = coder.decodeObject(forKey: "NS.mantissa") as? Data else {
+ return nil // raise "Critical NSDecimalNumber archived data is missing"
+ }
+ guard mantissaData.count == Int(NSDecimalMaxSize * 2) else {
+ return nil // raise "Critical NSDecimalNumber archived data is wrong size"
+ }
+ // Byte order?
+ let mantissa:(UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16) = (
+ UInt16(mantissaData[0]) << 8 & UInt16(mantissaData[1]),
+ UInt16(mantissaData[2]) << 8 & UInt16(mantissaData[3]),
+ UInt16(mantissaData[4]) << 8 & UInt16(mantissaData[5]),
+ UInt16(mantissaData[6]) << 8 & UInt16(mantissaData[7]),
+ UInt16(mantissaData[8]) << 8 & UInt16(mantissaData[9]),
+ UInt16(mantissaData[10]) << 8 & UInt16(mantissaData[11]),
+ UInt16(mantissaData[12]) << 8 & UInt16(mantissaData[13]),
+ UInt16(mantissaData[14]) << 8 & UInt16(mantissaData[15])
+ )
+ self.decimal = Decimal(_exponent: exponent, _length: length, _isNegative: isNegative, _isCompact: isCompact, _reserved: 0, _mantissa: mantissa)
+ super.init()
}
public required convenience init(floatLiteral value: Double) {
- NSUnimplemented()
+ self.init(decimal:Decimal(value))
}
public required convenience init(booleanLiteral value: Bool) {
- NSUnimplemented()
+ if value {
+ self.init(integerLiteral: 1)
+ } else {
+ self.init(integerLiteral: 0)
+ }
}
public required convenience init(integerLiteral value: Int) {
- NSUnimplemented()
+ self.init(decimal:Decimal(value))
}
public required convenience init(bytes buffer: UnsafeRawPointer, objCType type: UnsafePointer<Int8>) {
@@ -105,52 +162,180 @@
}
open override func description(withLocale locale: Locale?) -> String { NSUnimplemented() }
+
+ open class var zero: NSDecimalNumber {
+ return NSDecimalNumber(integerLiteral: 0)
+ }
+ open class var one: NSDecimalNumber {
+ return NSDecimalNumber(integerLiteral: 1)
+ }
+ open class var minimum: NSDecimalNumber {
+ return NSDecimalNumber(decimal:Decimal.leastFiniteMagnitude)
+ }
+ open class var maximum: NSDecimalNumber {
+ return NSDecimalNumber(decimal:Decimal.greatestFiniteMagnitude)
+
+ }
+ open class var notANumber: NSDecimalNumber {
+ return NSDecimalNumber(decimal: Decimal.nan)
+ }
- // TODO: "declarations from extensions cannot be overridden yet"
- // Although it's not clear we actually need to redeclare this here when the extension adds it to the superclass of this class
- // open var decimalValue: Decimal { NSUnimplemented() }
+ open func adding(_ other: NSDecimalNumber) -> NSDecimalNumber {
+ return adding(other, withBehavior: nil)
+ }
+ open func adding(_ other: NSDecimalNumber, withBehavior b: NSDecimalNumberBehaviors?) -> NSDecimalNumber {
+ var result = Decimal()
+ var left = self.decimal
+ var right = other.decimal
+ let behavior = b ?? NSDecimalNumber.defaultBehavior
+ let roundingMode = behavior.roundingMode()
+ let error = NSDecimalAdd(&result, &left, &right, roundingMode)
+ handle(error,behavior)
+ return NSDecimalNumber(decimal: result)
+ }
+
+ open func subtracting(_ other: NSDecimalNumber) -> NSDecimalNumber {
+ return subtracting(other, withBehavior: nil)
+ }
+ open func subtracting(_ other: NSDecimalNumber, withBehavior b: NSDecimalNumberBehaviors?) -> NSDecimalNumber {
+ var result = Decimal()
+ var left = self.decimal
+ var right = other.decimal
+ let behavior = b ?? NSDecimalNumber.defaultBehavior
+ let roundingMode = behavior.roundingMode()
+ let error = NSDecimalSubtract(&result, &left, &right, roundingMode)
+ handle(error,behavior)
+ return NSDecimalNumber(decimal: result)
+ }
+ open func multiplying(by other: NSDecimalNumber) -> NSDecimalNumber {
+ return multiplying(by: other, withBehavior: nil)
+ }
+ open func multiplying(by other: NSDecimalNumber, withBehavior b: NSDecimalNumberBehaviors?) -> NSDecimalNumber {
+ var result = Decimal()
+ var left = self.decimal
+ var right = other.decimal
+ let behavior = b ?? NSDecimalNumber.defaultBehavior
+ let roundingMode = behavior.roundingMode()
+ let error = NSDecimalMultiply(&result, &left, &right, roundingMode)
+ handle(error,behavior)
+ return NSDecimalNumber(decimal: result)
+ }
- open class var zero: NSDecimalNumber { NSUnimplemented() }
- open class var one: NSDecimalNumber { NSUnimplemented() }
- open class var minimum: NSDecimalNumber { NSUnimplemented() }
- open class var maximum: NSDecimalNumber { NSUnimplemented() }
- open class var notANumber: NSDecimalNumber { NSUnimplemented() }
+ open func dividing(by other: NSDecimalNumber) -> NSDecimalNumber {
+ return dividing(by: other, withBehavior: nil)
+ }
+ open func dividing(by other: NSDecimalNumber, withBehavior b: NSDecimalNumberBehaviors?) -> NSDecimalNumber {
+ var result = Decimal()
+ var left = self.decimal
+ var right = other.decimal
+ let behavior = b ?? NSDecimalNumber.defaultBehavior
+ let roundingMode = behavior.roundingMode()
+ let error = NSDecimalDivide(&result, &left, &right, roundingMode)
+ handle(error,behavior)
+ return NSDecimalNumber(decimal: result)
+ }
- open func adding(_ decimalNumber: NSDecimalNumber) -> NSDecimalNumber { NSUnimplemented() }
- open func adding(_ decimalNumber: NSDecimalNumber, withBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
-
- open func subtracting(_ decimalNumber: NSDecimalNumber) -> NSDecimalNumber { NSUnimplemented() }
- open func subtracting(_ decimalNumber: NSDecimalNumber, withBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
-
- open func multiplying(by decimalNumber: NSDecimalNumber) -> NSDecimalNumber { NSUnimplemented() }
- open func multiplying(by decimalNumber: NSDecimalNumber, withBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
-
- open func dividing(by decimalNumber: NSDecimalNumber) -> NSDecimalNumber { NSUnimplemented() }
- open func dividing(by decimalNumber: NSDecimalNumber, withBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
-
- open func raising(toPower power: Int) -> NSDecimalNumber { NSUnimplemented() }
- open func raising(toPower power: Int, withBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
-
- open func multiplying(byPowerOf10 power: Int16) -> NSDecimalNumber { NSUnimplemented() }
- open func multiplying(byPowerOf10 power: Int16, withBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
+ open func raising(toPower power: Int) -> NSDecimalNumber {
+ return raising(toPower:power, withBehavior: nil)
+ }
+ open func raising(toPower power: Int, withBehavior b: NSDecimalNumberBehaviors?) -> NSDecimalNumber {
+ var result = Decimal()
+ var input = self.decimal
+ let behavior = b ?? NSDecimalNumber.defaultBehavior
+ let roundingMode = behavior.roundingMode()
+ let error = NSDecimalPower(&result, &input, power, roundingMode)
+ handle(error,behavior)
+ return NSDecimalNumber(decimal: result)
+ }
+
+ open func multiplying(byPowerOf10 power: Int16) -> NSDecimalNumber {
+ return multiplying(byPowerOf10: power, withBehavior: nil)
+ }
+ open func multiplying(byPowerOf10 power: Int16, withBehavior b: NSDecimalNumberBehaviors?) -> NSDecimalNumber {
+ var result = Decimal()
+ var input = self.decimal
+ let behavior = b ?? NSDecimalNumber.defaultBehavior
+ let roundingMode = behavior.roundingMode()
+ let error = NSDecimalPower(&result, &input, Int(power), roundingMode)
+ handle(error,behavior)
+ return NSDecimalNumber(decimal: result)
+ }
open func rounding(accordingToBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
// Round to the scale of the behavior.
- open override func compare(_ decimalNumber: NSNumber) -> ComparisonResult { NSUnimplemented() }
// compare two NSDecimalNumbers
-
- open class var defaultBehavior: NSDecimalNumberBehaviors { NSUnimplemented() }
+ open override func compare(_ decimalNumber: NSNumber) -> ComparisonResult {
+ if let num = decimalNumber as? NSDecimalNumber {
+ return decimal.compare(to:num.decimal)
+ } else {
+ return decimal.compare(to:Decimal(decimalNumber.doubleValue))
+ }
+ }
+
+ open class var defaultBehavior: NSDecimalNumberBehaviors {
+ return NSDecimalNumberHandler.defaultBehavior
+ }
// One behavior per thread - The default behavior is
// rounding mode: NSRoundPlain
// scale: No defined scale (full precision)
// ignore exactnessException
// raise on overflow, underflow and divide by zero.
-
- open override var objCType: UnsafePointer<Int8> { NSUnimplemented() }
+ static let OBJC_TYPE = "d".utf8CString
+
+ open override var objCType: UnsafePointer<Int8> {
+ return NSDecimalNumber.OBJC_TYPE.withUnsafeBufferPointer{ $0.baseAddress! }
+ }
// return 'd' for double
- open override var doubleValue: Double { NSUnimplemented() }
+ open override var int8Value: Int8 {
+ return Int8(decimal.doubleValue)
+ }
+ open override var uint8Value: UInt8 {
+ return UInt8(decimal.doubleValue)
+ }
+ open override var int16Value: Int16 {
+ return Int16(decimal.doubleValue)
+ }
+ open override var uint16Value: UInt16 {
+ return UInt16(decimal.doubleValue)
+ }
+ open override var int32Value: Int32 {
+ return Int32(decimal.doubleValue)
+ }
+ open override var uint32Value: UInt32 {
+ return UInt32(decimal.doubleValue)
+ }
+ open override var int64Value: Int64 {
+ return Int64(decimal.doubleValue)
+ }
+ open override var uint64Value: UInt64 {
+ return UInt64(decimal.doubleValue)
+ }
+ open override var floatValue: Float {
+ return Float(decimal.doubleValue)
+ }
+ open override var doubleValue: Double {
+ return decimal.doubleValue
+ }
+ open override var boolValue: Bool {
+ return !decimal.isZero
+ }
+ open override var intValue: Int {
+ return Int(decimal.doubleValue)
+ }
+ open override var uintValue: UInt {
+ return UInt(decimal.doubleValue)
+ }
+
+ open override func isEqual(_ value: Any?) -> Bool {
+ if let number = value as? NSDecimalNumber {
+ return self.decimal == number.decimal
+ } else {
+ return false
+ }
+ }
+
}
// return an approximate double value
@@ -158,33 +343,103 @@
/*********** A class for defining common behaviors *******/
open class NSDecimalNumberHandler : NSObject, NSDecimalNumberBehaviors, NSCoding {
-
- public required init?(coder aDecoder: NSCoder) {
- NSUnimplemented()
+
+ static let defaultBehavior = NSDecimalNumberHandler()
+
+ let _roundingMode: NSDecimalNumber.RoundingMode
+ let _scale:Int16
+
+ let _raiseOnExactness: Bool
+ let _raiseOnOverflow: Bool
+ let _raiseOnUnderflow: Bool
+ let _raiseOnDivideByZero: Bool
+
+ public override init() {
+ _roundingMode = .plain
+ _scale = Int16(NSDecimalNoScale)
+
+ _raiseOnExactness = false
+ _raiseOnOverflow = true
+ _raiseOnUnderflow = true
+ _raiseOnDivideByZero = true
+ }
+ public required init?(coder: NSCoder) {
+ guard coder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+ _roundingMode = NSDecimalNumber.RoundingMode(rawValue: UInt(coder.decodeInteger(forKey: "NS.roundingMode")))!
+ if coder.containsValue(forKey: "NS.scale") {
+ _scale = Int16(coder.decodeInteger(forKey: "NS.scale"))
+ } else {
+ _scale = Int16(NSDecimalNoScale)
+ }
+ _raiseOnExactness = coder.decodeBool(forKey: "NS.raise.exactness")
+ _raiseOnOverflow = coder.decodeBool(forKey: "NS.raise.overflow")
+ _raiseOnUnderflow = coder.decodeBool(forKey: "NS.raise.underflow")
+ _raiseOnDivideByZero = coder.decodeBool(forKey: "NS.raise.dividebyzero")
}
- open func encode(with aCoder: NSCoder) {
- NSUnimplemented()
+ open func encode(with coder: NSCoder) {
+ guard coder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+ if _roundingMode != .plain {
+ coder.encode(Int(_roundingMode.rawValue), forKey: "NS.roundingmode")
+ }
+ if _scale != Int16(NSDecimalNoScale) {
+ coder.encode(_scale, forKey:"NS.scale")
+ }
+ if _raiseOnExactness {
+ coder.encode(_raiseOnExactness, forKey:"NS.raise.exactness")
+ }
+ if _raiseOnOverflow {
+ coder.encode(_raiseOnOverflow, forKey:"NS.raise.overflow")
+ }
+ if _raiseOnUnderflow {
+ coder.encode(_raiseOnUnderflow, forKey:"NS.raise.underflow")
+ }
+ if _raiseOnDivideByZero {
+ coder.encode(_raiseOnDivideByZero, forKey:"NS.raise.dividebyzero")
+ }
}
- open class func `default`() -> NSDecimalNumberHandler { NSUnimplemented() }
+ open class func `default`() -> NSDecimalNumberHandler {
+ return defaultBehavior
+ }
// rounding mode: NSRoundPlain
// scale: No defined scale (full precision)
// ignore exactnessException (return nil)
// raise on overflow, underflow and divide by zero.
- public init(roundingMode: NSDecimalNumber.RoundingMode, scale: Int16, raiseOnExactness exact: Bool, raiseOnOverflow overflow: Bool, raiseOnUnderflow underflow: Bool, raiseOnDivideByZero divideByZero: Bool) { NSUnimplemented() }
+ public init(roundingMode: NSDecimalNumber.RoundingMode, scale: Int16, raiseOnExactness exact: Bool, raiseOnOverflow overflow: Bool, raiseOnUnderflow underflow: Bool, raiseOnDivideByZero divideByZero: Bool) {
+ _roundingMode = roundingMode
+ _scale = scale
+ _raiseOnExactness = exact
+ _raiseOnOverflow = overflow
+ _raiseOnUnderflow = underflow
+ _raiseOnDivideByZero = divideByZero
+ }
- open func roundingMode() -> NSDecimalNumber.RoundingMode { NSUnimplemented() }
+ open func roundingMode() -> NSDecimalNumber.RoundingMode {
+ return _roundingMode
+ }
- open func scale() -> Int16 { NSUnimplemented() }
- // The scale could return NO_SCALE for no defined scale.
+ // The scale could return NoScale for no defined scale.
+ open func scale() -> Int16 {
+ return _scale
+ }
}
extension NSNumber {
- public var decimalValue: Decimal { NSUnimplemented() }
+ public var decimalValue: Decimal {
+ if let d = self as? NSDecimalNumber {
+ return d.decimal
+ } else {
+ return Decimal(self.doubleValue)
+ }
+ }
}
// Could be silently inexact for float and double.
diff --git a/Foundation/NSFileHandle.swift b/Foundation/NSFileHandle.swift
old mode 100644
new mode 100755
index 8596e66..dcc3e5d
--- a/Foundation/NSFileHandle.swift
+++ b/Foundation/NSFileHandle.swift
@@ -214,11 +214,49 @@
open class var standardError: FileHandle {
return _stderrFileHandle
}
-
+
+ internal static var _nulldeviceFileHandle: FileHandle = {
+ class NullDevice: FileHandle {
+ override var availableData: Data {
+ return Data()
+ }
+
+ override func readDataToEndOfFile() -> Data {
+ return Data()
+ }
+
+ override func readData(ofLength length: Int) -> Data {
+ return Data()
+ }
+
+ override func write(_ data: Data) {}
+
+ override var offsetInFile: UInt64 {
+ return 0
+ }
+
+ override func seekToEndOfFile() -> UInt64 {
+ return 0
+ }
+
+ override func seek(toFileOffset offset: UInt64) {}
+
+ override func truncateFile(atOffset offset: UInt64) {}
+
+ override func synchronizeFile() {}
+
+ override func closeFile() {}
+
+ deinit {}
+ }
+
+ return NullDevice(fileDescriptor: -1, closeOnDealloc: false)
+ }()
+
open class var nullDevice: FileHandle {
- NSUnimplemented()
+ return _nulldeviceFileHandle
}
-
+
public convenience init?(forReadingAtPath path: String) {
self.init(path: path, flags: O_RDONLY, createMode: 0)
}
diff --git a/Foundation/NSFileManager.swift b/Foundation/NSFileManager.swift
index 08b1f67..c40a1a3 100644
--- a/Foundation/NSFileManager.swift
+++ b/Foundation/NSFileManager.swift
@@ -125,7 +125,7 @@
for attribute in attributes.keys {
if attribute == .posixPermissions {
guard let number = attributes[attribute] as? NSNumber else {
- fatalError("Can't set file permissions to \(attributes[attribute])")
+ fatalError("Can't set file permissions to \(attributes[attribute] as Any?)")
}
#if os(OSX) || os(iOS)
let modeT = number.uint16Value
diff --git a/Foundation/NSKeyedArchiver.swift b/Foundation/NSKeyedArchiver.swift
index 550b412..f9b473b 100644
--- a/Foundation/NSKeyedArchiver.swift
+++ b/Foundation/NSKeyedArchiver.swift
@@ -241,8 +241,7 @@
}
private func _validateObjectSupportsSecureCoding(_ objv : Any?) {
- if objv != nil &&
- self.requiresSecureCoding &&
+ if let objv = objv, self.requiresSecureCoding &&
!NSKeyedArchiver._supportsSecureCoding(objv) {
fatalError("Secure coding required when encoding \(objv)")
}
@@ -271,7 +270,9 @@
return NSKeyedArchiveNullObjectReference
}
- uid = self._objRefMap[objv as! AnyHashable]
+ let value = _SwiftValue.store(objv)!
+
+ uid = self._objRefMap[value]
if uid == nil {
if conditional {
return nil // object has not been unconditionally encoded
@@ -279,7 +280,7 @@
uid = UInt32(self._objects.count)
- self._objRefMap[objv as! AnyHashable] = uid
+ self._objRefMap[value] = uid
self._objects.insert(NSKeyedArchiveNullObjectReferenceName, at: Int(uid!))
}
@@ -293,7 +294,7 @@
if objv == nil {
return true // always have a null reference
} else {
- return self._objRefMap[objv as! AnyHashable] != nil
+ return self._objRefMap[_SwiftValue.store(objv)] != nil
}
}
@@ -362,10 +363,10 @@
*/
private func replaceObject(_ object: Any, withObject replacement: Any?) {
if let unwrappedDelegate = self.delegate {
- unwrappedDelegate.archiver(self, willReplace: object as! AnyHashable, with: replacement)
+ unwrappedDelegate.archiver(self, willReplace: object, with: replacement)
}
- self._replacementMap[object as! AnyHashable] = replacement
+ self._replacementMap[_SwiftValue.store(object)] = replacement
}
/**
@@ -477,9 +478,8 @@
// object replaced by NSObject.replacementObjectForKeyedArchiver
// if it is replaced with nil, it cannot be further replaced
- if objectToEncode == nil {
- let ns = object as? NSObject
- objectToEncode = ns?.replacementObjectForKeyedArchiver(self)
+ if let ns = objectToEncode as? NSObject {
+ objectToEncode = ns.replacementObjectForKeyedArchiver(self)
if objectToEncode == nil {
replaceObject(object!, withObject: nil)
return nil
@@ -511,7 +511,12 @@
haveVisited = _haveVisited(objv)
object = _replacementObject(objv)
-
+
+ // bridge value types
+ if let bridgedObject = object as? _ObjectBridgeable {
+ object = bridgedObject._bridgeToAnyObject()
+ }
+
objectRef = _referenceObject(object, conditional: conditional)
guard let unwrappedObjectRef = objectRef else {
// we can return nil if the object is being conditionally encoded
@@ -532,12 +537,9 @@
_pushEncodingContext(innerEncodingContext)
codable.encode(with: self)
- guard let ns = object as? NSObject else {
- fatalError("Attempt to encode non-NSObject");
- }
-
- let cls : AnyClass = ns.classForKeyedArchiver ?? type(of: object) as! AnyClass
-
+ let ns = object as? NSObject
+ let cls : AnyClass = ns?.classForKeyedArchiver ?? type(of: object!) as! AnyClass
+
_setObjectInCurrentEncodingContext(_classReference(cls), forKey: "$class", escape: false)
_popEncodingContext()
encodedObject = innerEncodingContext.dict
diff --git a/Foundation/NSKeyedUnarchiver.swift b/Foundation/NSKeyedUnarchiver.swift
index 19a6527..b3dfc8e 100644
--- a/Foundation/NSKeyedUnarchiver.swift
+++ b/Foundation/NSKeyedUnarchiver.swift
@@ -375,7 +375,7 @@
unwrappedDelegate.unarchiver(self, willReplace: object, with: replacement)
}
- self._replacementMap[object as! AnyHashable] = replacement
+ self._replacementMap[_SwiftValue.store(object)] = replacement
}
private func _decodingError(_ code: CocoaError.Code, withDescription description: String) -> NSError {
@@ -392,7 +392,7 @@
}
// check replacement cache
- object = self._replacementMap[decodedObject as! AnyHashable]
+ object = self._replacementMap[_SwiftValue.store(decodedObject)]
if object != nil {
return object
}
@@ -418,7 +418,7 @@
if self.requiresSecureCoding && !supportsSecureCoding {
// FIXME should this be a fatal error?
- fatalError("Archiver \(self) requires secure coding but class \(classToConstruct) does not support it")
+ fatalError("Archiver \(self) requires secure coding but class \(classToConstruct as Optional) does not support it")
}
return supportsSecureCoding
@@ -489,9 +489,8 @@
}
} else {
// reference to a non-container object
- // FIXME remove these special cases
- if let str = dereferencedObject as? String {
- object = str._bridgeToObjectiveC()
+ if let bridgedObject = dereferencedObject as? _ObjectBridgeable {
+ object = bridgedObject._bridgeToAnyObject()
} else {
object = dereferencedObject
}
@@ -505,8 +504,7 @@
*/
private func _decodeObject(forKey key: String?) throws -> Any? {
guard let objectRef : Any? = _objectInCurrentDecodingContext(forKey: key) else {
- throw _decodingError(CocoaError.coderValueNotFound,
- withDescription: "No value found for key \(key). The data may be corrupt.")
+ throw _decodingError(CocoaError.coderValueNotFound, withDescription: "No value found for key \(key as Optional). The data may be corrupt.")
}
return try _decodeObject(objectRef!)
diff --git a/Foundation/NSLock.swift b/Foundation/NSLock.swift
index c4a9f68..e166b80 100644
--- a/Foundation/NSLock.swift
+++ b/Foundation/NSLock.swift
@@ -115,7 +115,7 @@
open func lock(before limit: Date) -> Bool {
_cond.lock()
- while _thread == nil {
+ while _thread != nil {
if !_cond.wait(until: limit) {
_cond.unlock()
return false
diff --git a/Foundation/NSNumber.swift b/Foundation/NSNumber.swift
index 724cc02..14bec84 100644
--- a/Foundation/NSNumber.swift
+++ b/Foundation/NSNumber.swift
@@ -290,7 +290,11 @@
super.init()
_CFNumberInitBool(_cfObject, value)
}
-
+
+ override internal init() {
+ super.init()
+ }
+
public required convenience init(bytes buffer: UnsafeRawPointer, objCType: UnsafePointer<Int8>) {
guard let type = _NSSimpleObjCType(UInt8(objCType.pointee)) else {
fatalError("NSNumber.init: unsupported type encoding spec '\(String(cString: objCType))'")
diff --git a/Foundation/NSString.swift b/Foundation/NSString.swift
index 32455e9..95f5e6c 100644
--- a/Foundation/NSString.swift
+++ b/Foundation/NSString.swift
@@ -817,7 +817,7 @@
return data
}
- return nil
+ return Data()
}
public func data(using encoding: UInt) -> Data? {
@@ -1008,8 +1008,10 @@
open func trimmingCharacters(in set: CharacterSet) -> String {
let len = length
var buf = _NSStringBuffer(string: self, start: 0, end: len)
- while !buf.isAtEnd && set.contains(UnicodeScalar(buf.currentCharacter)!) {
- buf.advance()
+ while !buf.isAtEnd,
+ let character = UnicodeScalar(buf.currentCharacter),
+ set.contains(character) {
+ buf.advance()
}
let startOfNonTrimmedRange = buf.location // This points at the first char not in the set
@@ -1018,8 +1020,10 @@
return ""
} else if startOfNonTrimmedRange < len - 1 {
buf.location = len - 1
- while set.contains(UnicodeScalar(buf.currentCharacter)!) && buf.location >= startOfNonTrimmedRange {
- buf.rewind()
+ while let character = UnicodeScalar(buf.currentCharacter),
+ set.contains(character),
+ buf.location >= startOfNonTrimmedRange {
+ buf.rewind()
}
let endOfNonTrimmedRange = buf.location
return substring(with: NSMakeRange(startOfNonTrimmedRange, endOfNonTrimmedRange + 1 - startOfNonTrimmedRange))
diff --git a/Foundation/NSURLCredential.swift b/Foundation/NSURLCredential.swift
index 300126a..32cd075 100644
--- a/Foundation/NSURLCredential.swift
+++ b/Foundation/NSURLCredential.swift
@@ -65,11 +65,32 @@
*/
public required init?(coder aDecoder: NSCoder) {
- NSUnimplemented()
+ guard aDecoder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+
+ func bridgeString(_ value: NSString) -> String? {
+ return String._unconditionallyBridgeFromObjectiveC(value)
+ }
+
+ let encodedUser = aDecoder.decodeObject(forKey: "NS._user") as! NSString
+ self._user = bridgeString(encodedUser)!
+
+ let encodedPassword = aDecoder.decodeObject(forKey: "NS._password") as! NSString
+ self._password = bridgeString(encodedPassword)!
+
+ let encodedPersistence = aDecoder.decodeObject(forKey: "NS._persistence") as! NSNumber
+ self._persistence = Persistence(rawValue: encodedPersistence.uintValue)!
}
open func encode(with aCoder: NSCoder) {
- NSUnimplemented()
+ guard aCoder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+
+ aCoder.encode(self._user._bridgeToObjectiveC(), forKey: "NS._user")
+ aCoder.encode(self._password._bridgeToObjectiveC(), forKey: "NS._password")
+ aCoder.encode(self._persistence.rawValue._bridgeToObjectiveC(), forKey: "NS._persistence")
}
static public var supportsSecureCoding: Bool {
@@ -84,6 +105,17 @@
return self
}
+ open override func isEqual(_ object: Any?) -> Bool {
+ if let other = object as? URLCredential {
+ return other === self
+ || (other._user == self._user
+ && other._password == self._password
+ && other._persistence == self._persistence)
+ }
+
+ return false
+ }
+
/*!
@method persistence
@abstract Determine whether this credential is or should be stored persistently
diff --git a/Foundation/NSURLSession/HTTPMessage.swift b/Foundation/NSURLSession/HTTPMessage.swift
index 4f41eef..6598d06 100644
--- a/Foundation/NSURLSession/HTTPMessage.swift
+++ b/Foundation/NSURLSession/HTTPMessage.swift
@@ -143,7 +143,12 @@
var headersAsDictionary: [String: String] {
var result: [String: String] = [:]
headers.forEach {
- result[$0.name] = $0.value
+ if result[$0.name] == nil {
+ result[$0.name] = $0.value
+ }
+ else {
+ result[$0.name]! += (", " + $0.value)
+ }
}
return result
}
@@ -287,8 +292,13 @@
var value: String?
let line = headView[headView.index(after: nameRange.upperBound)..<headView.endIndex]
if !line.isEmpty {
- guard let v = line.trimSPHTPrefix else { return nil }
- value = String(v)
+ if line.hasSPHTPrefix && line.count == 1 {
+ // to handle empty headers i.e header without value
+ value = String("")
+ } else {
+ guard let v = line.trimSPHTPrefix else { return nil }
+ value = String(v)
+ }
}
do {
var t = tail
diff --git a/Foundation/NSURLSession/NSURLSessionTask.swift b/Foundation/NSURLSession/NSURLSessionTask.swift
index f8b9569..27ad59f 100644
--- a/Foundation/NSURLSession/NSURLSessionTask.swift
+++ b/Foundation/NSURLSession/NSURLSessionTask.swift
@@ -88,7 +88,7 @@
originalRequest = nil
body = .none
workQueue = DispatchQueue(label: "URLSessionTask.notused.0")
- taskAttributesIsolation = DispatchQueue(label: "URLSessionTask.notused.1")
+ taskAttributesIsolation = DispatchQueue(label: "URLSessionTask.notused.1", attributes: DispatchQueue.Attributes.concurrent)
let fileName = NSTemporaryDirectory() + NSUUID().uuidString + ".tmp"
_ = FileManager.default.createFile(atPath: fileName, contents: nil)
self.tempFileURL = URL(fileURLWithPath: fileName)
@@ -145,7 +145,7 @@
return r
}
//TODO: dispatch_barrier_async
- set { taskAttributesIsolation.async { self._currentRequest = newValue } }
+ set { taskAttributesIsolation.async(flags: .barrier) { self._currentRequest = newValue } }
}
fileprivate var _currentRequest: URLRequest? = nil
/*@NSCopying*/ open fileprivate(set) var response: URLResponse? {
@@ -154,7 +154,7 @@
taskAttributesIsolation.sync { r = self._response }
return r
}
- set { taskAttributesIsolation.async { self._response = newValue } }
+ set { taskAttributesIsolation.async(flags: .barrier) { self._response = newValue } }
}
fileprivate var _response: URLResponse? = nil
@@ -170,7 +170,7 @@
taskAttributesIsolation.sync { r = self._countOfBytesReceived }
return r
}
- set { taskAttributesIsolation.async { self._countOfBytesReceived = newValue } }
+ set { taskAttributesIsolation.async(flags: .barrier) { self._countOfBytesReceived = newValue } }
}
fileprivate var _countOfBytesReceived: Int64 = 0
@@ -181,7 +181,7 @@
taskAttributesIsolation.sync { r = self._countOfBytesSent }
return r
}
- set { taskAttributesIsolation.async { self._countOfBytesSent = newValue } }
+ set { taskAttributesIsolation.async(flags: .barrier) { self._countOfBytesSent = newValue } }
}
fileprivate var _countOfBytesSent: Int64 = 0
@@ -213,7 +213,7 @@
taskAttributesIsolation.sync { r = self._state }
return r
}
- set { taskAttributesIsolation.async { self._state = newValue } }
+ set { taskAttributesIsolation.async(flags: .barrier) { self._state = newValue } }
}
fileprivate var _state: URLSessionTask.State = .suspended
@@ -298,7 +298,7 @@
return r
}
set {
- taskAttributesIsolation.async { self._priority = newValue }
+ taskAttributesIsolation.async(flags: .barrier) { self._priority = newValue }
}
}
fileprivate var _priority: Float = URLSessionTaskPriorityDefault
@@ -791,7 +791,7 @@
// to the delegate. But in case of redirects etc. we might send another
// request.
guard case .transferInProgress(let ts) = internalState else { fatalError("Transfer completed, but it wasn't in progress.") }
- guard let request = currentRequest else { fatalError("Transfer completed, but there's no currect request.") }
+ guard let request = currentRequest else { fatalError("Transfer completed, but there's no current request.") }
guard errorCode == nil else {
internalState = .transferFailed
failWith(errorCode: errorCode!, request: request)
diff --git a/Foundation/Notification.swift b/Foundation/Notification.swift
index 46cbc64..d929dbe 100644
--- a/Foundation/Notification.swift
+++ b/Foundation/Notification.swift
@@ -40,9 +40,12 @@
public var hashValue: Int {
return name.rawValue.hash
}
-
+
public var description: String {
- return "name = \(name.rawValue), object = \(object), userInfo = \(userInfo)"
+ var description = "name = \(name.rawValue)"
+ if let obj = object { description += ", object = \(obj)" }
+ if let info = userInfo { description += ", userInfo = \(info)" }
+ return description
}
public var debugDescription: String {
@@ -73,7 +76,17 @@
extension Notification : CustomReflectable {
public var customMirror: Mirror {
- NSUnimplemented()
+ var children: [(label: String?, value: Any)] = [(label: "name", self.name.rawValue)]
+
+ if let object = self.object {
+ children.append((label: "object", object))
+ }
+
+ if let info = self.userInfo {
+ children.append((label: "userInfo", info))
+ }
+
+ return Mirror(self, children: children, displayStyle: .class)
}
}
diff --git a/TestFoundation/TestNSCharacterSet.swift b/TestFoundation/TestNSCharacterSet.swift
index 71ff177..7bd9d62 100644
--- a/TestFoundation/TestNSCharacterSet.swift
+++ b/TestFoundation/TestNSCharacterSet.swift
@@ -28,7 +28,7 @@
("testRanges", testRanges),
("testInsertAndRemove", testInsertAndRemove),
("testBasics", testBasics),
-
+ ("testClosedRanges_SR_2988", testClosedRanges_SR_2988),
("test_Predefines", test_Predefines),
("test_Range", test_Range),
("test_String", test_String),
@@ -223,6 +223,18 @@
}
}
+ func testClosedRanges_SR_2988() {
+ // "CharacterSet.insert(charactersIn: ClosedRange) crashes on a closed ClosedRange<UnicodeScalar> containing U+D7FF"
+ let problematicChar = UnicodeScalar(0xD7FF)!
+ let range = capitalA...problematicChar
+ var characters = CharacterSet(charactersIn: range) // this should not crash
+ XCTAssertTrue(characters.contains(problematicChar))
+ characters.remove(charactersIn: range) // this should not crash
+ XCTAssertTrue(!characters.contains(problematicChar))
+ characters.insert(charactersIn: range) // this should not crash
+ XCTAssertTrue(characters.contains(problematicChar))
+ }
+
func test_Bitmap() {
}
diff --git a/TestFoundation/TestNSData.swift b/TestFoundation/TestNSData.swift
index 9705c15..44daab7 100644
--- a/TestFoundation/TestNSData.swift
+++ b/TestFoundation/TestNSData.swift
@@ -89,6 +89,7 @@
("test_replaceBytes", test_replaceBytes),
("test_initDataWithCapacity", test_initDataWithCapacity),
("test_initDataWithCount", test_initDataWithCount),
+ ("test_emptyStringToData", test_emptyStringToData),
]
}
@@ -438,6 +439,11 @@
return
}
}
+
+ func test_emptyStringToData() {
+ let data = "".data(using: .utf8)!
+ XCTAssertEqual(0, data.count, "data from empty string is empty")
+ }
}
// Tests from Swift SDK Overlay
diff --git a/TestFoundation/TestNSDecimal.swift b/TestFoundation/TestNSDecimal.swift
new file mode 100644
index 0000000..ffddd40
--- /dev/null
+++ b/TestFoundation/TestNSDecimal.swift
@@ -0,0 +1,608 @@
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+
+#if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
+ import Foundation
+ import XCTest
+#else
+ import SwiftFoundation
+ import SwiftXCTest
+#endif
+
+class TestNSDecimal: XCTestCase {
+
+ static var allTests : [(String, (TestNSDecimal) -> () throws -> Void)] {
+ return [
+ ("test_AdditionWithNormalization", test_AdditionWithNormalization),
+ ("test_BasicConstruction", test_BasicConstruction),
+ ("test_Constants", test_Constants),
+ ("test_Description", test_Description),
+ ("test_ExplicitConstruction", test_ExplicitConstruction),
+ ("test_Maths", test_Maths),
+ ("test_Misc", test_Misc),
+ ("test_MultiplicationOverflow", test_MultiplicationOverflow),
+ ("test_NaNInput", test_NaNInput),
+ ("test_NegativeAndZeroMultiplication", test_NegativeAndZeroMultiplication),
+ ("test_Normalise", test_Normalise),
+ ("test_NSDecimal", test_NSDecimal),
+ ("test_PositivePowers", test_PositivePowers),
+ ("test_RepeatingDivision", test_RepeatingDivision),
+ ("test_Round", test_Round),
+ ("test_SimpleMultiplication", test_SimpleMultiplication),
+ ("test_SmallerNumbers", test_SmallerNumbers),
+ ("test_ZeroPower", test_ZeroPower),
+ ]
+ }
+
+ func test_AdditionWithNormalization() {
+
+ let biggie = Decimal(65536)
+ let smallee = Decimal(65536)
+ let answer = biggie/smallee
+ XCTAssertEqual(Decimal(1),answer)
+
+ var one = Decimal(1)
+ var addend = Decimal(1)
+ var expected = Decimal()
+ var result = Decimal()
+
+ expected._isNegative = 0;
+ expected._isCompact = 0;
+
+ // 2 digits -- certain to work
+ addend._exponent = -1;
+ XCTAssertEqual(.noError, NSDecimalAdd(&result, &one, &addend, .plain), "1 + 0.1")
+ expected._exponent = -1;
+ expected._length = 1;
+ expected._mantissa.0 = 11;
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&expected, &result), "1.1 == 1 + 0.1")
+
+ // 38 digits -- guaranteed by NSDecimal to work
+ addend._exponent = -37;
+ XCTAssertEqual(.noError, NSDecimalAdd(&result, &one, &addend, .plain), "1 + 1e-37")
+ expected._exponent = -37;
+ expected._length = 8;
+ expected._mantissa.0 = 0x0001;
+ expected._mantissa.1 = 0x0000;
+ expected._mantissa.2 = 0x36a0;
+ expected._mantissa.3 = 0x00f4;
+ expected._mantissa.4 = 0x46d9;
+ expected._mantissa.5 = 0xd5da;
+ expected._mantissa.6 = 0xee10;
+ expected._mantissa.7 = 0x0785;
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&expected, &result), "1 + 1e-37")
+
+ // 39 digits -- not guaranteed to work but it happens to, so we make the test work either way
+ addend._exponent = -38;
+ let error = NSDecimalAdd(&result, &one, &addend, .plain)
+ XCTAssertTrue(error == .noError || error == .lossOfPrecision, "1 + 1e-38")
+ if error == .noError {
+ expected._exponent = -38;
+ expected._length = 8;
+ expected._mantissa.0 = 0x0001;
+ expected._mantissa.1 = 0x0000;
+ expected._mantissa.2 = 0x2240;
+ expected._mantissa.3 = 0x098a;
+ expected._mantissa.4 = 0xc47a;
+ expected._mantissa.5 = 0x5a86;
+ expected._mantissa.6 = 0x4ca8;
+ expected._mantissa.7 = 0x4b3b;
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&expected, &result), "1 + 1e-38")
+ } else {
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&one, &result), "1 + 1e-38")
+ }
+
+ // 40 digits -- doesn't work; need to make sure it's rounding for us
+ addend._exponent = -39;
+ XCTAssertEqual(.lossOfPrecision, NSDecimalAdd(&result, &one, &addend, .plain), "1 + 1e-39")
+ XCTAssertEqual("1", result.description)
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&one, &result), "1 + 1e-39")
+ }
+
+ func test_BasicConstruction() {
+ let zero = Decimal()
+ XCTAssertEqual(20, MemoryLayout<Decimal>.size)
+ XCTAssertEqual(0, zero._exponent)
+ XCTAssertEqual(0, zero._length)
+ XCTAssertEqual(0, zero._isNegative)
+ XCTAssertEqual(0, zero._isCompact)
+ XCTAssertEqual(0, zero._reserved)
+ let (m0, m1, m2, m3, m4, m5, m6, m7) = zero._mantissa
+ XCTAssertEqual(0, m0)
+ XCTAssertEqual(0, m1)
+ XCTAssertEqual(0, m2)
+ XCTAssertEqual(0, m3)
+ XCTAssertEqual(0, m4)
+ XCTAssertEqual(0, m5)
+ XCTAssertEqual(0, m6)
+ XCTAssertEqual(0, m7)
+ XCTAssertEqual(8, NSDecimalMaxSize)
+ XCTAssertEqual(32767, NSDecimalNoScale)
+ XCTAssertFalse(zero.isNormal)
+ XCTAssertTrue(zero.isFinite)
+ XCTAssertTrue(zero.isZero)
+ XCTAssertFalse(zero.isSubnormal)
+ XCTAssertFalse(zero.isInfinite)
+ XCTAssertFalse(zero.isNaN)
+ XCTAssertFalse(zero.isSignaling)
+ }
+ func test_Constants() {
+ XCTAssertEqual(8, NSDecimalMaxSize)
+ XCTAssertEqual(32767, NSDecimalNoScale)
+ let smallest = Decimal(_exponent: 127, _length: 8, _isNegative: 1, _isCompact: 1, _reserved: 0, _mantissa: (UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max))
+ XCTAssertEqual(smallest, Decimal.leastFiniteMagnitude)
+ let biggest = Decimal(_exponent: 127, _length: 8, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max))
+ XCTAssertEqual(biggest, Decimal.greatestFiniteMagnitude)
+ let leastNormal = Decimal(_exponent: -127, _length: 1, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (1, 0, 0, 0, 0, 0, 0, 0))
+ XCTAssertEqual(leastNormal, Decimal.leastNormalMagnitude)
+ let leastNonzero = Decimal(_exponent: -127, _length: 1, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (1, 0, 0, 0, 0, 0, 0, 0))
+ XCTAssertEqual(leastNonzero, Decimal.leastNonzeroMagnitude)
+ let pi = Decimal(_exponent: -38, _length: 8, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (0x6623, 0x7d57, 0x16e7, 0xad0d, 0xaf52, 0x4641, 0xdfa7, 0xec58))
+ XCTAssertEqual(pi, Decimal.pi)
+ XCTAssertEqual(10, Decimal.radix)
+ XCTAssertTrue(Decimal().isCanonical)
+ XCTAssertFalse(Decimal().isSignalingNaN)
+ XCTAssertFalse(Decimal.nan.isSignalingNaN)
+ XCTAssertTrue(Decimal.nan.isNaN)
+ XCTAssertEqual(.quietNaN, Decimal.nan.floatingPointClass)
+ XCTAssertEqual(.positiveZero, Decimal().floatingPointClass)
+ XCTAssertEqual(.negativeNormal, smallest.floatingPointClass)
+ XCTAssertEqual(.positiveNormal, biggest.floatingPointClass)
+ XCTAssertFalse(Double.nan.isFinite)
+ XCTAssertFalse(Double.nan.isInfinite)
+ }
+
+ func test_Description() {
+ XCTAssertEqual("0", Decimal().description)
+ XCTAssertEqual("0", Decimal(0).description)
+ XCTAssertEqual("10", Decimal(_exponent: 1, _length: 1, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (1, 0, 0, 0, 0, 0, 0, 0)).description)
+ XCTAssertEqual("10", Decimal(10).description)
+ XCTAssertEqual("123.458", Decimal(_exponent: -3, _length: 2, _isNegative: 0, _isCompact:1, _reserved: 0, _mantissa: (57922, 1, 0, 0, 0, 0, 0, 0)).description)
+ XCTAssertEqual("123.458", Decimal(123.458).description)
+ XCTAssertEqual("123", Decimal(UInt8(123)).description)
+ XCTAssertEqual("45", Decimal(Int8(45)).description)
+ XCTAssertEqual("3.14159265358979323846264338327950288419", Decimal.pi.description)
+ XCTAssertEqual("-30000000000", Decimal(sign: .minus, exponent: 10, significand: Decimal(3)).description)
+ XCTAssertEqual("300000", Decimal(sign: .plus, exponent: 5, significand: Decimal(3)).description)
+ XCTAssertEqual("5", Decimal(signOf: Decimal(3), magnitudeOf: Decimal(5)).description)
+ XCTAssertEqual("-5", Decimal(signOf: Decimal(-3), magnitudeOf: Decimal(5)).description)
+ XCTAssertEqual("5", Decimal(signOf: Decimal(3), magnitudeOf: Decimal(-5)).description)
+ XCTAssertEqual("-5", Decimal(signOf: Decimal(-3), magnitudeOf: Decimal(-5)).description)
+ }
+
+ func test_ExplicitConstruction() {
+ var explicit = Decimal(
+ _exponent: 0x17f,
+ _length: 0xff,
+ _isNegative: 3,
+ _isCompact: 4,
+ _reserved: UInt32(1<<18 + 1<<17 + 1),
+ _mantissa: (6, 7, 8, 9, 10, 11, 12, 13)
+ )
+ XCTAssertEqual(0x7f, explicit._exponent)
+ XCTAssertEqual(0x7f, explicit.exponent)
+ XCTAssertEqual(0x0f, explicit._length)
+ XCTAssertEqual(1, explicit._isNegative)
+ XCTAssertEqual(FloatingPointSign.minus, explicit.sign)
+ XCTAssertTrue(explicit.isSignMinus)
+ XCTAssertEqual(0, explicit._isCompact)
+ XCTAssertEqual(UInt32(1<<17 + 1), explicit._reserved)
+ let (m0, m1, m2, m3, m4, m5, m6, m7) = explicit._mantissa
+ XCTAssertEqual(6, m0)
+ XCTAssertEqual(7, m1)
+ XCTAssertEqual(8, m2)
+ XCTAssertEqual(9, m3)
+ XCTAssertEqual(10, m4)
+ XCTAssertEqual(11, m5)
+ XCTAssertEqual(12, m6)
+ XCTAssertEqual(13, m7)
+ explicit._isCompact = 5
+ explicit._isNegative = 6
+ XCTAssertEqual(0, explicit._isNegative)
+ XCTAssertEqual(1, explicit._isCompact)
+ XCTAssertEqual(FloatingPointSign.plus, explicit.sign)
+ XCTAssertFalse(explicit.isSignMinus)
+ XCTAssertTrue(explicit.isNormal)
+
+ let significand = explicit.significand
+ XCTAssertEqual(0, significand._exponent)
+ XCTAssertEqual(0, significand.exponent)
+ XCTAssertEqual(0x0f, significand._length)
+ XCTAssertEqual(0, significand._isNegative)
+ XCTAssertEqual(1, significand._isCompact)
+ XCTAssertEqual(0, significand._reserved)
+ let (sm0, sm1, sm2, sm3, sm4, sm5, sm6, sm7) = significand._mantissa
+ XCTAssertEqual(6, sm0)
+ XCTAssertEqual(7, sm1)
+ XCTAssertEqual(8, sm2)
+ XCTAssertEqual(9, sm3)
+ XCTAssertEqual(10, sm4)
+ XCTAssertEqual(11, sm5)
+ XCTAssertEqual(12, sm6)
+ XCTAssertEqual(13, sm7)
+
+ let ulp = explicit.ulp
+ XCTAssertEqual(0x7f, ulp.exponent)
+ XCTAssertEqual(8, ulp._length)
+ XCTAssertEqual(0, ulp._isNegative)
+ XCTAssertEqual(1, ulp._isCompact)
+ XCTAssertEqual(0, ulp._reserved)
+ XCTAssertEqual(1, ulp._mantissa.0)
+ XCTAssertEqual(0, ulp._mantissa.1)
+ XCTAssertEqual(0, ulp._mantissa.2)
+ XCTAssertEqual(0, ulp._mantissa.3)
+ XCTAssertEqual(0, ulp._mantissa.4)
+ XCTAssertEqual(0, ulp._mantissa.5)
+ XCTAssertEqual(0, ulp._mantissa.6)
+ XCTAssertEqual(0, ulp._mantissa.7)
+ }
+
+ func test_Maths() {
+ for i in -2...10 {
+ for j in 0...5 {
+ XCTAssertEqual(Decimal(i*j), Decimal(i) * Decimal(j), "\(Decimal(i*j)) == \(i) * \(j)")
+ XCTAssertEqual(Decimal(i+j), Decimal(i) + Decimal(j), "\(Decimal(i+j)) == \(i)+\(j)")
+ XCTAssertEqual(Decimal(i-j), Decimal(i) - Decimal(j), "\(Decimal(i-j)) == \(i)-\(j)")
+ if j != 0 {
+ let approximation = Decimal(Double(i)/Double(j))
+ let answer = Decimal(i) / Decimal(j)
+ let answerDescription = answer.description
+ let approximationDescription = approximation.description
+ var failed: Bool = false
+ var count = 0
+ let SIG_FIG = 14
+ for (a, b) in zip(answerDescription.characters, approximationDescription.characters) {
+ if a != b {
+ failed = true
+ break
+ }
+ if count == 0 && (a == "-" || a == "0" || a == ".") {
+ continue // don't count these as significant figures
+ }
+ if count >= SIG_FIG {
+ break
+ }
+ count += 1
+ }
+ XCTAssertFalse(failed, "\(Decimal(i/j)) == \(i)/\(j)")
+ }
+ }
+ }
+ XCTAssertEqual(Decimal(186243*15673), Decimal(186243) * Decimal(15673))
+ }
+
+ func test_Misc() {
+ XCTAssertEqual(.minus, Decimal(-5.2).sign)
+ XCTAssertEqual(.plus, Decimal(5.2).sign)
+ var d = Decimal(5.2)
+ XCTAssertEqual(.plus, d.sign)
+ d.negate()
+ XCTAssertEqual(.minus, d.sign)
+ d.negate()
+ XCTAssertEqual(.plus, d.sign)
+ XCTAssertTrue(Decimal(3.5).isEqual(to: Decimal(3.5)))
+ XCTAssertTrue(Decimal.nan.isEqual(to: Decimal.nan))
+ XCTAssertTrue(Decimal(1.28).isLess(than: Decimal(2.24)))
+ XCTAssertFalse(Decimal(2.28).isLess(than: Decimal(2.24)))
+ XCTAssertTrue(Decimal(1.28).isTotallyOrdered(belowOrEqualTo: Decimal(2.24)))
+ XCTAssertFalse(Decimal(2.28).isTotallyOrdered(belowOrEqualTo: Decimal(2.24)))
+ XCTAssertTrue(Decimal(1.2).isTotallyOrdered(belowOrEqualTo: Decimal(1.2)))
+ XCTAssertTrue(Decimal.nan.isEqual(to: Decimal.nan))
+ XCTAssertTrue(Decimal.nan.isLess(than: Decimal(0)))
+ XCTAssertFalse(Decimal.nan.isLess(than: Decimal.nan))
+ XCTAssertTrue(Decimal.nan.isLessThanOrEqualTo(Decimal(0)))
+ XCTAssertTrue(Decimal.nan.isLessThanOrEqualTo(Decimal.nan))
+ XCTAssertFalse(Decimal.nan.isTotallyOrdered(belowOrEqualTo: Decimal.nan))
+ XCTAssertFalse(Decimal.nan.isTotallyOrdered(belowOrEqualTo: Decimal(2.3)))
+ XCTAssertTrue(Decimal(2) < Decimal(3))
+ XCTAssertTrue(Decimal(3) > Decimal(2))
+ XCTAssertEqual(3275573729074, Decimal(1234).hashValue)
+ XCTAssertEqual(Decimal(-9), Decimal(1) - Decimal(10))
+ XCTAssertEqual(Decimal(3), Decimal(2).nextUp)
+ XCTAssertEqual(Decimal(2), Decimal(3).nextDown)
+ XCTAssertEqual(Decimal(-476), Decimal(1024).distance(to: Decimal(1500)))
+ XCTAssertEqual(Decimal(68040), Decimal(386).advanced(by: Decimal(67654)))
+ XCTAssertEqual(Decimal(1.234), abs(Decimal(1.234)))
+ XCTAssertEqual(Decimal(1.234), abs(Decimal(-1.234)))
+ var a = Decimal(1234)
+ XCTAssertEqual(.noError, NSDecimalMultiplyByPowerOf10(&a, &a, 1, .plain))
+ XCTAssertEqual(Decimal(12340), a)
+ a = Decimal(1234)
+ XCTAssertEqual(.noError, NSDecimalMultiplyByPowerOf10(&a, &a, 2, .plain))
+ XCTAssertEqual(Decimal(123400), a)
+ XCTAssertEqual(.overflow, NSDecimalMultiplyByPowerOf10(&a, &a, 128, .plain))
+ XCTAssertTrue(a.isNaN)
+ a = Decimal(1234)
+ XCTAssertEqual(.noError, NSDecimalMultiplyByPowerOf10(&a, &a, -2, .plain))
+ XCTAssertEqual(Decimal(12.34), a)
+ XCTAssertEqual(.underflow, NSDecimalMultiplyByPowerOf10(&a, &a, -128, .plain))
+ XCTAssertTrue(a.isNaN)
+ a = Decimal(1234)
+ XCTAssertEqual(.noError, NSDecimalPower(&a, &a, 0, .plain))
+ XCTAssertEqual(Decimal(1), a)
+ a = Decimal(8)
+ XCTAssertEqual(.noError, NSDecimalPower(&a, &a, 2, .plain))
+ XCTAssertEqual(Decimal(64), a)
+ a = Decimal(-2)
+ XCTAssertEqual(.noError, NSDecimalPower(&a, &a, 3, .plain))
+ XCTAssertEqual(Decimal(-8), a)
+ for i in -2...10 {
+ for j in 0...5 {
+ var actual = Decimal(i)
+ XCTAssertEqual(.noError, NSDecimalPower(&actual, &actual, j, .plain))
+ let expected = Decimal(pow(Double(i), Double(j)))
+ XCTAssertEqual(expected, actual, "\(actual) == \(i)^\(j)")
+ }
+ }
+ }
+
+ func test_MultiplicationOverflow() {
+ var multiplicand = Decimal(_exponent: 0, _length: 8, _isNegative: 0, _isCompact: 0, _reserved: 0, _mantissa: ( 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff ))
+
+ var result = Decimal()
+ var multiplier = Decimal(1)
+
+ multiplier._mantissa.0 = 2
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &multiplicand, &multiplier, .plain), "2 * max mantissa")
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &multiplier, &multiplicand, .plain), "max mantissa * 2")
+
+ multiplier._exponent = 0x7f
+ XCTAssertEqual(.overflow, NSDecimalMultiply(&result, &multiplicand, &multiplier, .plain), "2e127 * max mantissa")
+ XCTAssertEqual(.overflow, NSDecimalMultiply(&result, &multiplier, &multiplicand, .plain), "max mantissa * 2e127")
+ }
+
+ func test_NaNInput() {
+ var NaN = Decimal.nan
+ var one = Decimal(1)
+ var result = Decimal()
+
+ XCTAssertNotEqual(.noError, NSDecimalAdd(&result, &NaN, &one, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN + 1")
+ XCTAssertNotEqual(.noError, NSDecimalAdd(&result, &one, &NaN, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "1 + NaN")
+
+ XCTAssertNotEqual(.noError, NSDecimalSubtract(&result, &NaN, &one, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN - 1")
+ XCTAssertNotEqual(.noError, NSDecimalSubtract(&result, &one, &NaN, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "1 - NaN")
+
+ XCTAssertNotEqual(.noError, NSDecimalMultiply(&result, &NaN, &one, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN * 1")
+ XCTAssertNotEqual(.noError, NSDecimalMultiply(&result, &one, &NaN, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "1 * NaN")
+
+ XCTAssertNotEqual(.noError, NSDecimalDivide(&result, &NaN, &one, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN / 1")
+ XCTAssertNotEqual(.noError, NSDecimalDivide(&result, &one, &NaN, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "1 / NaN")
+
+ XCTAssertNotEqual(.noError, NSDecimalPower(&result, &NaN, 0, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN ^ 0")
+ XCTAssertNotEqual(.noError, NSDecimalPower(&result, &NaN, 4, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN ^ 4")
+ XCTAssertNotEqual(.noError, NSDecimalPower(&result, &NaN, 5, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN ^ 5")
+
+ XCTAssertNotEqual(.noError, NSDecimalMultiplyByPowerOf10(&result, &NaN, 0, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN e0")
+ XCTAssertNotEqual(.noError, NSDecimalMultiplyByPowerOf10(&result, &NaN, 4, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN e4")
+ XCTAssertNotEqual(.noError, NSDecimalMultiplyByPowerOf10(&result, &NaN, 5, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN e5")
+ }
+
+ func test_NegativeAndZeroMultiplication() {
+ var one = Decimal(1)
+ var zero = Decimal(0)
+ var negativeOne = Decimal(-1)
+
+ var result = Decimal()
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &one, &one, .plain), "1 * 1")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&one, &result), "1 * 1")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &one, &negativeOne, .plain), "1 * -1")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&negativeOne, &result), "1 * -1")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &negativeOne, &one, .plain), "-1 * 1")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&negativeOne, &result), "-1 * 1")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &negativeOne, &negativeOne, .plain), "-1 * -1")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&one, &result), "-1 * -1")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &one, &zero, .plain), "1 * 0")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&zero, &result), "1 * 0")
+ XCTAssertEqual(0, result._isNegative, "1 * 0")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &zero, &one, .plain), "0 * 1")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&zero, &result), "0 * 1")
+ XCTAssertEqual(0, result._isNegative, "0 * 1")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &negativeOne, &zero, .plain), "-1 * 0")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&zero, &result), "-1 * 0")
+ XCTAssertEqual(0, result._isNegative, "-1 * 0")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &zero, &negativeOne, .plain), "0 * -1")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&zero, &result), "0 * -1")
+ XCTAssertEqual(0, result._isNegative, "0 * -1")
+ }
+
+ func test_Normalise() {
+ var one = Decimal(1)
+ var ten = Decimal(-10)
+ XCTAssertEqual(.noError, NSDecimalNormalize(&one, &ten, .plain))
+ XCTAssertEqual(Decimal(1), one)
+ XCTAssertEqual(Decimal(-10), ten)
+ XCTAssertEqual(1, one._length)
+ XCTAssertEqual(1, ten._length)
+ one = Decimal(1)
+ ten = Decimal(10)
+ XCTAssertEqual(.noError, NSDecimalNormalize(&one, &ten, .plain))
+ XCTAssertEqual(Decimal(1), one)
+ XCTAssertEqual(Decimal(10), ten)
+ XCTAssertEqual(1, one._length)
+ XCTAssertEqual(1, ten._length)
+ }
+
+ func test_NSDecimal() {
+ var nan = Decimal.nan
+ XCTAssertTrue(NSDecimalIsNotANumber(&nan))
+ var zero = Decimal()
+ XCTAssertFalse(NSDecimalIsNotANumber(&zero))
+ var three = Decimal(3)
+ var guess = Decimal()
+ NSDecimalCopy(&guess, &three)
+ XCTAssertEqual(three, guess)
+
+ var f = Decimal(_exponent: 0, _length: 2, _isNegative: 0, _isCompact: 0, _reserved: 0, _mantissa: (0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000))
+ let before = f.description
+ XCTAssertEqual(0, f._isCompact)
+ NSDecimalCompact(&f)
+ XCTAssertEqual(1, f._isCompact)
+ let after = f.description
+ XCTAssertEqual(before, after)
+ }
+
+ func test_PositivePowers() {
+ let six = NSDecimalNumber(integerLiteral: 6)
+
+ XCTAssertEqual(6, six.raising(toPower:1).intValue)
+ XCTAssertEqual(36, six.raising(toPower:2).intValue)
+ XCTAssertEqual(216, six.raising(toPower:3).intValue)
+ XCTAssertEqual(1296, six.raising(toPower:4).intValue)
+ XCTAssertEqual(7776, six.raising(toPower:5).intValue)
+ XCTAssertEqual(46656, six.raising(toPower:6).intValue)
+ XCTAssertEqual(279936, six.raising(toPower:7).intValue)
+ XCTAssertEqual(1679616, six.raising(toPower:8).intValue)
+ XCTAssertEqual(10077696, six.raising(toPower:9).intValue)
+
+ let negativeSix = NSDecimalNumber(integerLiteral: -6)
+
+ XCTAssertEqual(-6, negativeSix.raising(toPower:1).intValue)
+ XCTAssertEqual(36, negativeSix.raising(toPower:2).intValue)
+ XCTAssertEqual(-216, negativeSix.raising(toPower:3).intValue)
+ XCTAssertEqual(1296, negativeSix.raising(toPower:4).intValue)
+ XCTAssertEqual(-7776, negativeSix.raising(toPower:5).intValue)
+ XCTAssertEqual(46656, negativeSix.raising(toPower:6).intValue)
+ XCTAssertEqual(-279936, negativeSix.raising(toPower:7).intValue)
+ XCTAssertEqual(1679616, negativeSix.raising(toPower:8).intValue)
+ XCTAssertEqual(-10077696, negativeSix.raising(toPower:9).intValue)
+ }
+
+ func test_RepeatingDivision() {
+ let repeatingNumerator = Decimal(16)
+ let repeatingDenominator = Decimal(9)
+ let repeating = repeatingNumerator / repeatingDenominator
+
+ let numerator = Decimal(1010)
+ var result = numerator / repeating
+
+ var expected = Decimal()
+ expected._exponent = -35;
+ expected._length = 8;
+ expected._isNegative = 0;
+ expected._isCompact = 1;
+ expected._reserved = 0;
+ expected._mantissa.0 = 51946;
+ expected._mantissa.1 = 3;
+ expected._mantissa.2 = 15549;
+ expected._mantissa.3 = 55864;
+ expected._mantissa.4 = 57984;
+ expected._mantissa.5 = 55436;
+ expected._mantissa.6 = 45186;
+ expected._mantissa.7 = 10941;
+
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&expected, &result), "568.12500000000000000000000000000248554: \(expected.description) != \(result.description)");
+ }
+
+ func test_Round() {
+ let testCases = [
+ // expected, start, scale, round
+ ( 0, 0.5, 0, Decimal.RoundingMode.down ),
+ ( 1, 0.5, 0, Decimal.RoundingMode.up ),
+ ( 2, 2.5, 0, Decimal.RoundingMode.bankers ),
+ ( 4, 3.5, 0, Decimal.RoundingMode.bankers ),
+ ( 5, 5.2, 0, Decimal.RoundingMode.plain ),
+ ( 4.5, 4.5, 1, Decimal.RoundingMode.down ),
+ ( 5.5, 5.5, 1, Decimal.RoundingMode.up ),
+ ( 6.5, 6.5, 1, Decimal.RoundingMode.plain ),
+ ( 7.5, 7.5, 1, Decimal.RoundingMode.bankers ),
+
+ ( -1, -0.5, 0, Decimal.RoundingMode.down ),
+ ( -2, -2.5, 0, Decimal.RoundingMode.up ),
+ ( -3, -2.5, 0, Decimal.RoundingMode.bankers ),
+ ( -4, -3.5, 0, Decimal.RoundingMode.bankers ),
+ ( -5, -5.2, 0, Decimal.RoundingMode.plain ),
+ ( -4.5, -4.5, 1, Decimal.RoundingMode.down ),
+ ( -5.5, -5.5, 1, Decimal.RoundingMode.up ),
+ ( -6.5, -6.5, 1, Decimal.RoundingMode.plain ),
+ ( -7.5, -7.5, 1, Decimal.RoundingMode.bankers ),
+ ]
+ for testCase in testCases {
+ let (expected, start, scale, mode) = testCase
+ var num = Decimal(start)
+ NSDecimalRound(&num, &num, scale, mode)
+ XCTAssertEqual(Decimal(expected), num)
+ }
+ }
+
+ func test_SimpleMultiplication() {
+ var multiplicand = Decimal()
+ multiplicand._isNegative = 0
+ multiplicand._isCompact = 0
+ multiplicand._length = 1
+ multiplicand._exponent = 1
+
+ var multiplier = multiplicand
+ multiplier._exponent = 2
+
+ var expected = multiplicand
+ expected._isNegative = 0
+ expected._isCompact = 0
+ expected._exponent = 3
+ expected._length = 1
+
+ var result = Decimal()
+
+ for i in 1..<UInt8.max {
+ multiplicand._mantissa.0 = UInt16(i)
+
+ for j in 1..<UInt8.max {
+ multiplier._mantissa.0 = UInt16(j)
+ expected._mantissa.0 = UInt16(i) * UInt16(j)
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &multiplicand, &multiplier, .plain), "\(i) * \(j)")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&expected, &result), "\(expected._mantissa.0) == \(i) * \(j)");
+ }
+ }
+ }
+
+ func test_SmallerNumbers() {
+ var number = NSDecimalNumber(booleanLiteral:true)
+ XCTAssertTrue(number.boolValue, "Should have received true")
+
+ number = NSDecimalNumber(mantissa:0, exponent:0, isNegative:false)
+ XCTAssertFalse(number.boolValue, "Should have received false")
+
+ number = NSDecimalNumber(mantissa:1, exponent:0, isNegative:false)
+ XCTAssertTrue(number.boolValue, "Should have received true")
+
+ XCTAssertEqual(100,number.objCType.pointee, "ObjC type for NSDecimalNumber is 'd'")
+ }
+
+ func test_ZeroPower() {
+ let six = NSDecimalNumber(integerLiteral: 6)
+ XCTAssertEqual(1, six.raising(toPower: 0))
+
+ let negativeSix = NSDecimalNumber(integerLiteral: -6)
+ XCTAssertEqual(1, negativeSix.raising(toPower: 0))
+ }
+
+}
diff --git a/TestFoundation/TestNSFileHandle.swift b/TestFoundation/TestNSFileHandle.swift
old mode 100644
new mode 100755
index 69a74cc..93357ff
--- a/TestFoundation/TestNSFileHandle.swift
+++ b/TestFoundation/TestNSFileHandle.swift
@@ -19,6 +19,7 @@
static var allTests : [(String, (TestNSFileHandle) -> () throws -> ())] {
return [
("test_pipe", test_pipe),
+ ("test_nullDevice", test_nullDevice),
]
}
@@ -38,4 +39,23 @@
XCTAssertEqual(output, input)
}
}
+
+ func test_nullDevice() {
+ let fh = FileHandle.nullDevice
+
+ XCTAssertEqual(fh.fileDescriptor, -1)
+ fh.closeFile()
+ fh.seek(toFileOffset: 10)
+ XCTAssertEqual(fh.offsetInFile, 0)
+ XCTAssertEqual(fh.seekToEndOfFile(), 0)
+ XCTAssertEqual(fh.readData(ofLength: 15).count, 0)
+ fh.synchronizeFile()
+
+ fh.write(Data(bytes: [1,2]))
+ fh.seek(toFileOffset: 0)
+ XCTAssertEqual(fh.availableData.count, 0)
+ fh.write(Data(bytes: [1,2]))
+ fh.seek(toFileOffset: 0)
+ XCTAssertEqual(fh.readDataToEndOfFile().count, 0)
+ }
}
diff --git a/TestFoundation/TestNSKeyedArchiver.swift b/TestFoundation/TestNSKeyedArchiver.swift
index 19ba3d0..6e6b529 100644
--- a/TestFoundation/TestNSKeyedArchiver.swift
+++ b/TestFoundation/TestNSKeyedArchiver.swift
@@ -16,7 +16,7 @@
import SwiftXCTest
#endif
-public class UserClass : NSObject, NSSecureCoding {
+public class NSUserClass : NSObject, NSSecureCoding {
var ivar : Int
public class var supportsSecureCoding: Bool {
@@ -37,12 +37,12 @@
public override var description: String {
get {
- return "UserClass \(ivar)"
+ return "NSUserClass \(ivar)"
}
}
public override func isEqual(_ object: Any?) -> Bool {
- if let custom = object as? UserClass {
+ if let custom = object as? NSUserClass {
return self.ivar == custom.ivar
} else {
return false
@@ -50,6 +50,40 @@
}
}
+public class UserClass : CustomStringConvertible, Equatable, Hashable, NSSecureCoding {
+ var ivar : Int
+
+ public class var supportsSecureCoding: Bool {
+ return true
+ }
+
+ public func encode(with aCoder : NSCoder) {
+ aCoder.encode(ivar, forKey:"$ivar") // also test escaping
+ }
+
+ init(_ value: Int) {
+ self.ivar = value
+ }
+
+ public required init?(coder aDecoder: NSCoder) {
+ self.ivar = aDecoder.decodeInteger(forKey: "$ivar")
+ }
+
+ public var description: String {
+ get {
+ return "UserClass \(ivar)"
+ }
+ }
+
+ public static func ==(lhs: UserClass, rhs: UserClass) -> Bool {
+ return lhs.ivar == rhs.ivar
+ }
+
+ public var hashValue: Int {
+ return ivar
+ }
+}
+
class TestNSKeyedArchiver : XCTestCase {
static var allTests: [(String, (TestNSKeyedArchiver) -> () throws -> Void)] {
return [
@@ -62,6 +96,7 @@
("test_archive_string", test_archive_string),
("test_archive_mutable_array", test_archive_mutable_array),
("test_archive_mutable_dictionary", test_archive_mutable_dictionary),
+ ("test_archive_ns_user_class", test_archive_ns_user_class),
("test_archive_nspoint", test_archive_nspoint),
("test_archive_nsrange", test_archive_nsrange),
("test_archive_nsrect", test_archive_nsrect),
@@ -69,7 +104,8 @@
("test_archive_set", test_archive_set),
("test_archive_url", test_archive_url),
("test_archive_user_class", test_archive_user_class),
- ("test_archive_uuid", test_archive_uuid),
+ ("test_archive_uuid_bvref", test_archive_uuid_byref),
+ ("test_archive_uuid_byvalue", test_archive_uuid_byvalue),
]
}
@@ -85,7 +121,7 @@
XCTAssertTrue(decode(unarchiver))
}
- private func test_archive(_ object: NSObject, classes: [AnyClass], allowsSecureCoding: Bool = true, outputFormat: PropertyListSerialization.PropertyListFormat) {
+ private func test_archive(_ object: Any, classes: [AnyClass], allowsSecureCoding: Bool = true, outputFormat: PropertyListSerialization.PropertyListFormat) {
test_archive({ archiver -> Bool in
archiver.requiresSecureCoding = allowsSecureCoding
archiver.outputFormat = outputFormat
@@ -97,12 +133,12 @@
unarchiver.requiresSecureCoding = allowsSecureCoding
do {
- let rootObj = try unarchiver.decodeTopLevelObject(of: classes, forKey: NSKeyedArchiveRootObjectKey)
- guard let root = rootObj as? NSObject else {
+ guard let rootObj = try unarchiver.decodeTopLevelObject(of: classes, forKey: NSKeyedArchiveRootObjectKey) else {
XCTFail("Unable to decode data")
return false
}
- XCTAssertEqual(object, root, "unarchived object \(root) does not match \(object)")
+
+ XCTAssertEqual(object as? AnyHashable, rootObj as? AnyHashable, "unarchived object \(rootObj) does not match \(object)")
} catch {
XCTFail("Error thrown: \(error)")
}
@@ -110,13 +146,13 @@
})
}
- private func test_archive(_ object: NSObject, classes: [AnyClass], allowsSecureCoding: Bool = true) {
+ private func test_archive(_ object: Any, classes: [AnyClass], allowsSecureCoding: Bool = true) {
// test both XML and binary encodings
test_archive(object, classes: classes, allowsSecureCoding: allowsSecureCoding, outputFormat: PropertyListSerialization.PropertyListFormat.xml)
test_archive(object, classes: classes, allowsSecureCoding: allowsSecureCoding, outputFormat: PropertyListSerialization.PropertyListFormat.binary)
}
- private func test_archive(_ object: NSObject, allowsSecureCoding: Bool = true) {
+ private func test_archive(_ object: AnyObject, allowsSecureCoding: Bool = true) {
return test_archive(object, classes: [type(of: object)], allowsSecureCoding: allowsSecureCoding)
}
@@ -252,8 +288,18 @@
test_archive(userClass)
}
- func test_archive_uuid() {
+ func test_archive_ns_user_class() {
+ let nsUserClass = NSUserClass(5678)
+ test_archive(nsUserClass)
+ }
+
+ func test_archive_uuid_byref() {
let uuid = NSUUID()
test_archive(uuid)
}
+
+ func test_archive_uuid_byvalue() {
+ let uuid = UUID()
+ return test_archive(uuid, classes: [NSUUID.self])
+ }
}
diff --git a/TestFoundation/TestNSRange.swift b/TestFoundation/TestNSRange.swift
index 5ce2ae4..927e989 100644
--- a/TestFoundation/TestNSRange.swift
+++ b/TestFoundation/TestNSRange.swift
@@ -23,7 +23,13 @@
return [
// currently disabled due to pending requirements for NSString
// ("test_NSRangeFromString", test_NSRangeFromString ),
- ("test_NSRangeBridging", test_NSRangeBridging)
+ ("test_NSRangeBridging", test_NSRangeBridging),
+ ("test_NSMaxRange", test_NSMaxRange),
+ ("test_NSLocationInRange", test_NSLocationInRange),
+ ("test_NSEqualRanges", test_NSEqualRanges),
+ ("test_NSUnionRange", test_NSUnionRange),
+ ("test_NSIntersectionRange", test_NSIntersectionRange),
+ ("test_NSStringFromRange", test_NSStringFromRange),
]
}
@@ -66,4 +72,69 @@
let swiftRange2 = range.toRange()
XCTAssertEqual(swiftRange, swiftRange2)
}
+
+ func test_NSMaxRange() {
+ let ranges = [(NSMakeRange(0, 3), 3),
+ (NSMakeRange(7, 8), 15),
+ (NSMakeRange(56, 1), 57)]
+ for (range, result) in ranges {
+ XCTAssertEqual(NSMaxRange(range), result)
+ }
+ }
+
+ func test_NSLocationInRange() {
+ let ranges = [(3, NSMakeRange(0, 5), true),
+ (10, NSMakeRange(2, 9), true),
+ (7, NSMakeRange(2, 5), false),
+ (5, NSMakeRange(5, 1), true)];
+ for (location, range, result) in ranges {
+ XCTAssertEqual(NSLocationInRange(location, range), result);
+ }
+ }
+
+ func test_NSEqualRanges() {
+ let ranges = [(NSMakeRange(0, 3), NSMakeRange(0, 3), true),
+ (NSMakeRange(0, 4), NSMakeRange(0, 8), false),
+ (NSMakeRange(3, 6), NSMakeRange(3, 10), false),
+ (NSMakeRange(0, 5), NSMakeRange(7, 8), false)]
+ for (first, second, result) in ranges {
+ XCTAssertEqual(NSEqualRanges(first, second), result)
+ }
+ }
+
+
+ func test_NSUnionRange() {
+ let ranges = [(NSMakeRange(0, 5), NSMakeRange(3, 8), NSMakeRange(0, 11)),
+ (NSMakeRange(6, 10), NSMakeRange(3, 8), NSMakeRange(3, 13)),
+ (NSMakeRange(3, 8), NSMakeRange(6, 10), NSMakeRange(3, 13)),
+ (NSMakeRange(0, 5), NSMakeRange(7, 8), NSMakeRange(0, 15)),
+ (NSMakeRange(0, 3), NSMakeRange(1, 2), NSMakeRange(0, 3))]
+ for (first, second, result) in ranges {
+ XCTAssert(NSEqualRanges(NSUnionRange(first, second), result))
+ }
+ }
+
+ func test_NSIntersectionRange() {
+ let ranges = [(NSMakeRange(0, 5), NSMakeRange(3, 8), NSMakeRange(3, 2)),
+ (NSMakeRange(6, 10), NSMakeRange(3, 8), NSMakeRange(6, 5)),
+ (NSMakeRange(3, 8), NSMakeRange(6, 10), NSMakeRange(6, 5)),
+ (NSMakeRange(0, 5), NSMakeRange(7, 8), NSMakeRange(0, 0)),
+ (NSMakeRange(0, 3), NSMakeRange(1, 2), NSMakeRange(1, 2))]
+ for (first, second, result) in ranges {
+ XCTAssert(NSEqualRanges(NSIntersectionRange(first, second), result))
+ }
+ }
+
+ func test_NSStringFromRange() {
+ let ranges = ["{0, 0}": NSMakeRange(0, 0),
+ "{6, 4}": NSMakeRange(6, 4),
+ "{0, 10}": NSMakeRange(0, 10),
+ "{10, 200}": NSMakeRange(10, 200),
+ "{100, 10}": NSMakeRange(100, 10),
+ "{1000, 100000}": NSMakeRange(1000, 100_000)];
+
+ for (string, range) in ranges {
+ XCTAssertEqual(NSStringFromRange(range), string)
+ }
+ }
}
diff --git a/TestFoundation/TestNSString.swift b/TestFoundation/TestNSString.swift
index 49acf78..ebb8fab 100644
--- a/TestFoundation/TestNSString.swift
+++ b/TestFoundation/TestNSString.swift
@@ -81,7 +81,11 @@
("test_resolvingSymlinksInPath", test_resolvingSymlinksInPath),
("test_expandingTildeInPath", test_expandingTildeInPath),
("test_standardizingPath", test_standardizingPath),
- ("test_removingPercentEncoding", test_removingPercentEncoding),
+ ("test_addingPercentEncoding", test_addingPercentEncoding),
+ ("test_removingPercentEncodingInLatin", test_removingPercentEncodingInLatin),
+ ("test_removingPercentEncodingInNonLatin", test_removingPercentEncodingInNonLatin),
+ ("test_removingPersentEncodingWithoutEncoding", test_removingPersentEncodingWithoutEncoding),
+ ("test_addingPercentEncodingAndBack", test_addingPercentEncodingAndBack),
("test_stringByAppendingPathExtension", test_stringByAppendingPathExtension),
("test_deletingPathExtension", test_deletingPathExtension),
("test_ExternalRepresentation", test_ExternalRepresentation),
@@ -602,6 +606,9 @@
let characterSet = CharacterSet.whitespaces
let string: NSString = " abc "
XCTAssertEqual(string.trimmingCharacters(in: characterSet), "abc")
+
+ let emojiString: NSString = " \u{1F62C} "
+ XCTAssertEqual(emojiString.trimmingCharacters(in: characterSet), "\u{1F62C}")
}
func test_initializeWithFormat() {
@@ -864,15 +871,68 @@
}
}
- func test_removingPercentEncoding() {
+ func test_addingPercentEncoding() {
+ let s1 = "a b".addingPercentEncoding(withAllowedCharacters: .alphanumerics)
+ XCTAssertEqual(s1, "a%20b")
+
+ let s2 = "\u{0434}\u{043E}\u{043C}".addingPercentEncoding(withAllowedCharacters: .alphanumerics)
+ XCTAssertEqual(s2, "%D0%B4%D0%BE%D0%BC")
+ }
+
+ func test_removingPercentEncodingInLatin() {
let s1 = "a%20b".removingPercentEncoding
XCTAssertEqual(s1, "a b")
let s2 = "a%1 b".removingPercentEncoding
XCTAssertNil(s2, "returns nil for a string with an invalid percent encoding")
}
+ func test_removingPercentEncodingInNonLatin() {
+ let s1 = "\u{043C}\u{043E}\u{0439}%20\u{0434}\u{043E}\u{043C}".removingPercentEncoding
+ XCTAssertEqual(s1, "\u{043C}\u{043E}\u{0439} \u{0434}\u{043E}\u{043C}")
+
+ let s2 = "%D0%B4%D0%BE%D0%BC".removingPercentEncoding
+ XCTAssertEqual(s2, "\u{0434}\u{043E}\u{043C}")
+
+ let s3 = "\u{00E0}a%1 b".removingPercentEncoding
+ XCTAssertNil(s3, "returns nil for a string with an invalid percent encoding")
+ }
+
+ func test_removingPersentEncodingWithoutEncoding() {
+ let cyrillicString = "\u{0434}\u{043E}\u{043C}"
+ let cyrillicEscapedString = cyrillicString.removingPercentEncoding
+ XCTAssertEqual(cyrillicString, cyrillicEscapedString)
+
+ let chineseString = "\u{623F}\u{5B50}"
+ let chineseEscapedString = chineseString.removingPercentEncoding
+ XCTAssertEqual(chineseString, chineseEscapedString)
+
+ let arabicString = "\u{0645}\u{0646}\u{0632}\u{0644}"
+ let arabicEscapedString = arabicString.removingPercentEncoding
+ XCTAssertEqual(arabicString, arabicEscapedString)
+
+ let randomString = "\u{00E0}\u{00E6}"
+ let randomEscapedString = randomString.removingPercentEncoding
+ XCTAssertEqual(randomString, randomEscapedString)
+
+ let latinString = "home"
+ let latinEscapedString = latinString.removingPercentEncoding
+ XCTAssertEqual(latinString, latinEscapedString)
+ }
+
+ func test_addingPercentEncodingAndBack() {
+ let latingString = "a b"
+ let escapedLatingString = latingString.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
+ let returnedLatingString = escapedLatingString?.removingPercentEncoding
+ XCTAssertEqual(returnedLatingString, latingString)
+
+ let cyrillicString = "\u{0434}\u{043E}\u{043C}"
+ let escapedCyrillicString = cyrillicString.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
+ let returnedCyrillicString = escapedCyrillicString?.removingPercentEncoding
+ XCTAssertEqual(returnedCyrillicString, cyrillicString)
+ }
+
func test_stringByAppendingPathExtension() {
- let values : Dictionary = [
+ let values = [
NSString(string: "/tmp/scratch.old") : "/tmp/scratch.old.tiff",
NSString(string: "/tmp/scratch.") : "/tmp/scratch..tiff",
NSString(string: "/tmp/") : "/tmp.tiff",
@@ -882,7 +942,7 @@
]
for (fileName, expectedResult) in values {
let result = fileName.appendingPathExtension("tiff")
- XCTAssertEqual(result, expectedResult, "expected \(expectedResult) for \(fileName) but got \(result)")
+ XCTAssertEqual(result, expectedResult, "expected \(expectedResult) for \(fileName) but got \(result as Optional)")
}
}
diff --git a/TestFoundation/TestNSTimeZone.swift b/TestFoundation/TestNSTimeZone.swift
index 41ac367..2f6968b 100644
--- a/TestFoundation/TestNSTimeZone.swift
+++ b/TestFoundation/TestNSTimeZone.swift
@@ -47,7 +47,7 @@
let tz = NSTimeZone.system
let abbreviation1 = tz.abbreviation()
let abbreviation2 = tz.abbreviation(for: Date())
- XCTAssertEqual(abbreviation1, abbreviation2, "\(abbreviation1) should be equal to \(abbreviation2)")
+ XCTAssertEqual(abbreviation1, abbreviation2, "\(abbreviation1 as Optional) should be equal to \(abbreviation2 as Optional)")
}
func test_abbreviationDictionary() {
@@ -98,7 +98,7 @@
let abbreviation1 = tz.abbreviation()
let abbreviation2 = obj.abbreviation
- XCTAssertEqual(abbreviation1, abbreviation2, "\(abbreviation1) should be equal to \(abbreviation2)")
+ XCTAssertEqual(abbreviation1, abbreviation2, "\(abbreviation1 as Optional) should be equal to \(abbreviation2 as Optional)")
let isDaylightSavingTime1 = tz.isDaylightSavingTime()
let isDaylightSavingTime2 = obj.isDaylightSavingTime
@@ -112,7 +112,7 @@
let nextDaylightSavingTimeTransition1 = tz.nextDaylightSavingTimeTransition
let nextDaylightSavingTimeTransition2 = obj.nextDaylightSavingTimeTransition
let nextDaylightSavingTimeTransition3 = tz.nextDaylightSavingTimeTransition(after: Date())
- XCTAssert(nextDaylightSavingTimeTransition1 == nextDaylightSavingTimeTransition2 || nextDaylightSavingTimeTransition2 == nextDaylightSavingTimeTransition3, "\(nextDaylightSavingTimeTransition1) should be equal to \(nextDaylightSavingTimeTransition2), or in the rare circumstance where a daylight saving time transition has just occurred, \(nextDaylightSavingTimeTransition2) should be equal to \(nextDaylightSavingTimeTransition3)")
+ XCTAssert(nextDaylightSavingTimeTransition1 == nextDaylightSavingTimeTransition2 || nextDaylightSavingTimeTransition2 == nextDaylightSavingTimeTransition3, "\(nextDaylightSavingTimeTransition1 as Optional) should be equal to \(nextDaylightSavingTimeTransition2 as Optional), or in the rare circumstance where a daylight saving time transition has just occurred, \(nextDaylightSavingTimeTransition2 as Optional) should be equal to \(nextDaylightSavingTimeTransition3 as Optional)")
}
func test_knownTimeZoneNames() {
@@ -137,18 +137,18 @@
func test_initializingTimeZoneWithOffset() {
let tz = TimeZone(identifier: "GMT-0400")
XCTAssertNotNil(tz)
- let seconds = tz?.secondsFromGMT(for: Date())
+ let seconds = tz?.secondsFromGMT(for: Date()) ?? 0
XCTAssertEqual(seconds, -14400, "GMT-0400 should be -14400 seconds but got \(seconds) instead")
let tz2 = TimeZone(secondsFromGMT: -14400)
XCTAssertNotNil(tz2)
let expectedName = "GMT-0400"
let actualName = tz2?.identifier
- XCTAssertEqual(actualName, expectedName, "expected name \"\(expectedName)\" is not equal to \"\(actualName)\"")
+ XCTAssertEqual(actualName, expectedName, "expected name \"\(expectedName)\" is not equal to \"\(actualName as Optional)\"")
let expectedLocalizedName = "GMT-04:00"
let actualLocalizedName = tz2?.localizedName(for: .generic, locale: Locale(identifier: "en_US"))
- XCTAssertEqual(actualLocalizedName, expectedLocalizedName, "expected name \"\(expectedLocalizedName)\" is not equal to \"\(actualLocalizedName)\"")
- let seconds2 = tz2?.secondsFromGMT()
+ XCTAssertEqual(actualLocalizedName, expectedLocalizedName, "expected name \"\(expectedLocalizedName)\" is not equal to \"\(actualLocalizedName as Optional)\"")
+ let seconds2 = tz2?.secondsFromGMT() ?? 0
XCTAssertEqual(seconds2, -14400, "GMT-0400 should be -14400 seconds but got \(seconds2) instead")
let tz3 = TimeZone(identifier: "GMT-9999")
@@ -161,8 +161,9 @@
XCTAssertNil(tz)
// Test valid timezone abbreviation of "AST" for "America/Halifax"
tz = TimeZone(abbreviation: "AST")
- let expectedName = "America/Halifax"
- XCTAssertEqual(tz?.identifier, expectedName, "expected name \"\(expectedName)\" is not equal to \"\(tz?.identifier)\"")
+ let expectedIdentifier = "America/Halifax"
+ let actualIdentifier = tz?.identifier
+ XCTAssertEqual(actualIdentifier, expectedIdentifier, "expected identifier \"\(expectedIdentifier)\" is not equal to \"\(actualIdentifier as Optional)\"")
}
func test_systemTimeZoneUsesSystemTime() {
diff --git a/TestFoundation/TestNSURL.swift b/TestFoundation/TestNSURL.swift
index 9c7c10f..87409b5 100644
--- a/TestFoundation/TestNSURL.swift
+++ b/TestFoundation/TestNSURL.swift
@@ -153,7 +153,7 @@
}
if let stringObj = obj as? String {
if stringObj != got[key] {
- differences.append(" \(key) Expected = '\(stringObj)', Got = '\(got[key])'")
+ differences.append(" \(key) Expected = '\(stringObj)', Got = '\(got[key] as Optional)'")
}
}
}
@@ -442,7 +442,7 @@
var url = URLComponents(string: urlString)
url!.port = port
let receivedString = url!.string
- XCTAssertEqual(receivedString, expectedString, "expected \(expectedString) but received \(receivedString)")
+ XCTAssertEqual(receivedString, expectedString, "expected \(expectedString) but received \(receivedString as Optional)")
}
func test_url() {
@@ -454,7 +454,7 @@
compWithAuthority!.path = "/path/to/file with space.html"
compWithAuthority!.query = "id=23&search=Foo Bar"
var expectedString = "https://www.swift.org/path/to/file%20with%20space.html?id=23&search=Foo%20Bar"
- XCTAssertEqual(compWithAuthority!.string, expectedString, "expected \(expectedString) but received \(compWithAuthority!.string)")
+ XCTAssertEqual(compWithAuthority!.string, expectedString, "expected \(expectedString) but received \(compWithAuthority!.string as Optional)")
var aURL = compWithAuthority!.url(relativeTo: baseURL)
XCTAssertNotNil(aURL)
@@ -474,7 +474,7 @@
compWithoutAuthority.path = "path/to/file with space.html"
compWithoutAuthority.query = "id=23&search=Foo Bar"
expectedString = "path/to/file%20with%20space.html?id=23&search=Foo%20Bar"
- XCTAssertEqual(compWithoutAuthority.string, expectedString, "expected \(expectedString) but received \(compWithoutAuthority.string)")
+ XCTAssertEqual(compWithoutAuthority.string, expectedString, "expected \(expectedString) but received \(compWithoutAuthority.string as Optional)")
aURL = compWithoutAuthority.url(relativeTo: baseURL)
XCTAssertNotNil(aURL)
diff --git a/TestFoundation/TestNSURLCredential.swift b/TestFoundation/TestNSURLCredential.swift
index 542c857..037b114 100644
--- a/TestFoundation/TestNSURLCredential.swift
+++ b/TestFoundation/TestNSURLCredential.swift
@@ -21,7 +21,8 @@
static var allTests: [(String, (TestNSURLCredential) -> () throws -> Void)] {
return [
("test_construction", test_construction),
- ("test_copy", test_copy)
+ ("test_copy", test_copy),
+ ("test_NSCoding", test_NSCoding)
]
}
@@ -39,4 +40,10 @@
let copy = credential.copy() as! URLCredential
XCTAssertTrue(copy.isEqual(credential))
}
+
+ func test_NSCoding() {
+ let credentialA = URLCredential(user: "swiftUser", password: "swiftPassword", persistence: .forSession)
+ let credentialB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: credentialA)) as! URLCredential
+ XCTAssertEqual(credentialA, credentialB, "Archived then unarchived url credential must be equal.")
+ }
}
diff --git a/TestFoundation/TestNSXMLDocument.swift b/TestFoundation/TestNSXMLDocument.swift
index 3a6b20a..a493dcd 100644
--- a/TestFoundation/TestNSXMLDocument.swift
+++ b/TestFoundation/TestNSXMLDocument.swift
@@ -161,7 +161,7 @@
element.insertChildren([foo, bar], at: 1)
XCTAssertEqual(element.children?[1], foo)
XCTAssertEqual(element.children?[2], bar)
- XCTAssertEqual(element.children?[0], baz, "\(element.children?[0])")
+ XCTAssertEqual(element.children?[0], baz)
let faz = XMLElement(name: "faz")
element.replaceChild(at: 2, with: faz)
@@ -239,7 +239,7 @@
XCTAssertEqual(element.attributes?.last, bazAttribute)
element.setAttributesWith(["hello": "world", "foobar": "buzbaz"])
- XCTAssertEqual(element.attribute(forName:"hello")?.stringValue, "world", "\(element.attribute(forName:"hello")?.stringValue)")
+ XCTAssertEqual(element.attribute(forName:"hello")?.stringValue, "world", "\(element.attribute(forName:"hello")?.stringValue as Optional)")
XCTAssertEqual(element.attribute(forName:"foobar")?.stringValue, "buzbaz", "\(element.attributes ?? [])")
}
diff --git a/TestFoundation/TestNotification.swift b/TestFoundation/TestNotification.swift
new file mode 100644
index 0000000..9c1bd38
--- /dev/null
+++ b/TestFoundation/TestNotification.swift
@@ -0,0 +1,56 @@
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+
+
+
+#if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
+ import Foundation
+ import XCTest
+#else
+ import SwiftFoundation
+ import SwiftXCTest
+#endif
+
+
+
+class TestNotification : XCTestCase {
+
+ static var allTests: [(String, (TestNotification) -> () throws -> Void)] {
+ return [
+ ("test_customReflection", test_customReflection),
+ ]
+ }
+
+ func test_customReflection() {
+ let someName = "somenotifname"
+ let targetObject = NSObject()
+ let userInfo = ["hello": "world", "indexThis": 350] as [AnyHashable: Any]
+ let notif = Notification(name: Notification.Name(rawValue: someName), object: targetObject, userInfo: userInfo)
+ let mirror = notif.customMirror
+
+ XCTAssertEqual(mirror.displayStyle, .class)
+ XCTAssertNil(mirror.superclassMirror)
+
+ var children = Array(mirror.children).makeIterator()
+ let firstChild = children.next()
+ let secondChild = children.next()
+ let thirdChild = children.next()
+ XCTAssertEqual(firstChild?.label, "name")
+ XCTAssertEqual(firstChild?.value as? String, someName)
+
+ XCTAssertEqual(secondChild?.label, "object")
+ XCTAssertEqual(secondChild?.value as? NSObject, targetObject)
+
+ XCTAssertEqual(thirdChild?.label, "userInfo")
+ XCTAssertEqual((thirdChild?.value as? [AnyHashable: Any])?["hello"] as? String, "world")
+ XCTAssertEqual((thirdChild?.value as? [AnyHashable: Any])?["indexThis"] as? Int, 350)
+
+ }
+
+}
diff --git a/TestFoundation/TestObjCRuntime.swift b/TestFoundation/TestObjCRuntime.swift
new file mode 100644
index 0000000..21c0042
--- /dev/null
+++ b/TestFoundation/TestObjCRuntime.swift
@@ -0,0 +1,53 @@
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+
+#if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
+ import Foundation
+ import XCTest
+#else
+ import SwiftFoundation
+ import SwiftXCTest
+#endif
+
+class SwiftClass {
+ class InnerClass {}
+}
+
+struct SwfitStruct {}
+
+enum SwiftEnum {}
+
+class TestObjCRuntime: XCTestCase {
+ static var allTests: [(String, (TestObjCRuntime) -> () throws -> Void)] {
+ return [
+ ("testStringFromClass", testStringFromClass),
+ ("testClassFromString", testClassFromString),
+ ]
+ }
+
+ func testStringFromClass() {
+ XCTAssertEqual(NSStringFromClass(NSObject.self), "NSObject")
+ XCTAssertEqual(NSStringFromClass(SwiftClass.self), "TestFoundation.SwiftClass")
+#if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
+ XCTAssertEqual(NSStringFromClass(XCTestCase.self), "XCTest.XCTestCase");
+#else
+ XCTAssertEqual(NSStringFromClass(XCTestCase.self), "SwiftXCTest.XCTestCase");
+#endif
+ }
+
+ func testClassFromString() {
+ XCTAssertNotNil(NSClassFromString("NSObject"))
+ XCTAssertNotNil(NSClassFromString("TestFoundation.SwiftClass"))
+ XCTAssertNil(NSClassFromString("TestFoundation.SwiftClass.InnerClass"))
+ XCTAssertNil(NSClassFromString("SwiftClass"))
+ XCTAssertNil(NSClassFromString("MadeUpClassName"))
+ XCTAssertNil(NSClassFromString("SwiftStruct"));
+ XCTAssertNil(NSClassFromString("SwiftEnum"));
+ }
+}
diff --git a/TestFoundation/main.swift b/TestFoundation/main.swift
index 5e325c4..732bf17 100644
--- a/TestFoundation/main.swift
+++ b/TestFoundation/main.swift
@@ -32,6 +32,7 @@
testCase(TestNSDate.allTests),
testCase(TestNSDateComponents.allTests),
testCase(TestNSDateFormatter.allTests),
+ testCase(TestNSDecimal.allTests),
testCase(TestNSDictionary.allTests),
testCase(TestNSFileManager.allTests),
testCase(TestNSGeometry.allTests),
@@ -85,4 +86,6 @@
testCase(TestUnitConverter.allTests),
testCase(TestProgressFraction.allTests),
testCase(TestProgress.allTests),
+ testCase(TestObjCRuntime.allTests),
+ testCase(TestNotification.allTests),
])