Files
swift-mirror/stdlib/public/SDK/Foundation/Decimal.swift
Philippe Hausler dc783c064c [Foundation] Remove @_silgen thunks and replace them with shims instead
This avoids indirection by making calls directly to the C implementations which prevents potentials of mismatched intent or changes of calling convention of @_silgen. The added benefit is that all of the shims in this case are no longer visible symbols (anyone using them was not authorized out side of the Foundation overlay). Also the callout methods in the headers now all share similar naming shcemes for easier refactoring and searching in the style of __NS<class><action> style. The previous compiled C/Objective-C source files were built with MRR the new headers MUST be ARC by Swift import rules.

The one caveat is that certain functions MUST avoid the bridge case (since they are part of the bridging code-paths and that would incur a recursive potential) which have the types erased up to NSObject * via the macro NS_NON_BRIDGED.

The remaining @_silgen declarations are either swift functions exposed externally to the rest of Swift’s runtime or are included in NSNumber.gyb which the Foundation team has other plans for removing those @_silgen functions at a later date and Data.swift has one external function left with @_silgen which is blocked by a bug in the compiler which seems to improperly import that particular method as an inline c function.
2017-03-06 09:59:37 -08:00

447 lines
15 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
@_exported import Foundation // Clang module
import _SwiftCoreFoundationOverlayShims
extension Decimal {
public typealias RoundingMode = NSDecimalNumber.RoundingMode
public typealias CalculationError = NSDecimalNumber.CalculationError
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(_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))
}
@available(*, unavailable, message: "Decimal does not yet fully adopt FloatingPoint.")
public mutating func formTruncatingRemainder(dividingBy other: Decimal) { fatalError("Decimal does not yet fully adopt FloatingPoint") }
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 {
var lhs = self
var rhs = other
return NSDecimalCompare(&lhs, &rhs) == .orderedSame
}
public func isLess(than other: Decimal) -> Bool {
var lhs = self
var rhs = other
return NSDecimalCompare(&lhs, &rhs) == .orderedAscending
}
public func isLessThanOrEqualTo(_ other: Decimal) -> Bool {
var lhs = self
var rhs = other
let order = NSDecimalCompare(&lhs, &rhs)
return order == .orderedAscending || order == .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 res = Decimal()
var leftOp = lhs
var rightOp = rhs
NSDecimalAdd(&res, &leftOp, &rightOp, .plain)
return res
}
public static func -(lhs: Decimal, rhs: Decimal) -> Decimal {
var res = Decimal()
var leftOp = lhs
var rightOp = rhs
NSDecimalSubtract(&res, &leftOp, &rightOp, .plain)
return res
}
public static func /(lhs: Decimal, rhs: Decimal) -> Decimal {
var res = Decimal()
var leftOp = lhs
var rightOp = rhs
NSDecimalDivide(&res, &leftOp, &rightOp, .plain)
return res
}
public static func *(lhs: Decimal, rhs: Decimal) -> Decimal {
var res = Decimal()
var leftOp = lhs
var rightOp = rhs
NSDecimalMultiply(&res, &leftOp, &rightOp, .plain)
return res
}
}
public func pow(_ x: Decimal, _ y: Int) -> Decimal {
var res = Decimal()
var num = x
NSDecimalPower(&res, &num, y, .plain)
return res
}
extension Decimal : Hashable, Comparable {
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)
case 1:
d = d * 65536 + Double(_mantissa.1)
case 2:
d = d * 65536 + Double(_mantissa.2)
case 3:
d = d * 65536 + Double(_mantissa.3)
case 4:
d = d * 65536 + Double(_mantissa.4)
case 5:
d = d * 65536 + Double(_mantissa.5)
case 6:
d = d * 65536 + Double(_mantissa.6)
case 7:
d = d * 65536 + Double(_mantissa.7)
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 {
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) {
self.init(value)
}
}
extension Decimal : ExpressibleByIntegerLiteral {
public init(integerLiteral value: Int) {
self.init(value)
}
}
extension Decimal : SignedNumber { }
extension Decimal : Strideable {
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 {
return Decimal(_exponent: x._exponent, _length: x._length, _isNegative: 0, _isCompact: x._isCompact, _reserved: 0, _mantissa: x._mantissa)
}
}
extension Decimal {
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(_exponent: 0, _length: 0, _isNegative: 0, _isCompact: 0, _reserved: 0, _mantissa: (0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000))
} else {
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 = UInt32(0)
// this is a bit ugly but it is the closest approximation of the C initializer that can be expressed here.
_mantissa = (0, 0, 0, 0, 0, 0, 0, 0)
while mantissa != 0 && i < 8 /* NSDecimalMaxSize */ {
switch i {
case 0:
_mantissa.0 = UInt16(mantissa & 0xffff)
case 1:
_mantissa.1 = UInt16(mantissa & 0xffff)
case 2:
_mantissa.2 = UInt16(mantissa & 0xffff)
case 3:
_mantissa.3 = UInt16(mantissa & 0xffff)
case 4:
_mantissa.4 = UInt16(mantissa & 0xffff)
case 5:
_mantissa.5 = UInt16(mantissa & 0xffff)
case 6:
_mantissa.6 = UInt16(mantissa & 0xffff)
case 7:
_mantissa.7 = UInt16(mantissa & 0xffff)
default:
fatalError("initialization overflow")
}
mantissa = mantissa >> 16
i += 1
}
_length = i
_isNegative = negative ? 1 : 0
_isCompact = 0
_exponent = Int32(exponent)
NSDecimalCompact(&self)
}
}
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))
}
@available(*, unavailable, message: "Decimal does not yet fully adopt FloatingPoint.")
public static var infinity: Decimal { fatalError("Decimal does not yet fully adopt FloatingPoint") }
@available(*, unavailable, message: "Decimal does not yet fully adopt FloatingPoint.")
public static var signalingNaN: Decimal { fatalError("Decimal does not yet fully adopt FloatingPoint") }
public var isSignalingNaN: Bool {
return false
}
public static var nan: Decimal {
return quietNaN
}
public static var quietNaN: Decimal {
return Decimal(_exponent: 0, _length: 0, _isNegative: 1, _isCompact: 0, _reserved: 0, _mantissa: (0, 0, 0, 0, 0, 0, 0, 0))
}
/// The IEEE 754 "class" of this type.
public var floatingPointClass: FloatingPointClassification {
if _length == 0 && _isNegative == 1 {
return .quietNaN
} else if _length == 0 {
return .positiveZero
}
// NSDecimal does not really represent normal and subnormal in the same manner as the IEEE standard, for now we can probably claim normal for any nonzero, nonnan values
if _isNegative == 1 {
return .negativeNormal
} else {
return .positiveNormal
}
}
/// `true` iff `self` is negative.
public var isSignMinus: Bool { return _isNegative != 0 }
/// `true` iff `self` is normal (not zero, subnormal, infinity, or
/// NaN).
public var isNormal: Bool { return !isZero && !isInfinite && !isNaN }
/// `true` iff `self` is zero, subnormal, or normal (not infinity
/// or NaN).
public var isFinite: Bool { return !isNaN }
/// `true` iff `self` is +0.0 or -0.0.
public var isZero: Bool { return _length == 0 && _isNegative == 0 }
/// `true` iff `self` is subnormal.
public var isSubnormal: Bool { return false }
/// `true` iff `self` is infinity.
public var isInfinite: Bool { return false }
/// `true` iff `self` is NaN.
public var isNaN: Bool { return _length == 0 && _isNegative == 1 }
/// `true` iff `self` is a signaling NaN.
public var isSignaling: Bool { return false }
}
extension Decimal : CustomStringConvertible {
public init?(string: String, locale: Locale? = nil) {
let scan = Scanner(string: string)
var theDecimal = Decimal()
scan.locale = locale
if !scan.scanDecimal(&theDecimal) {
return nil
}
self = theDecimal
}
public var description: String {
var val = self
return NSDecimalString(&val, nil)
}
}
extension Decimal : _ObjectiveCBridgeable {
@_semantics("convertToObjectiveC")
public func _bridgeToObjectiveC() -> NSDecimalNumber {
return NSDecimalNumber(decimal: self)
}
public static func _forceBridgeFromObjectiveC(_ x: NSDecimalNumber, result: inout Decimal?) {
if !_conditionallyBridgeFromObjectiveC(x, result: &result) {
fatalError("Unable to bridge \(_ObjectiveCType.self) to \(self)")
}
}
public static func _conditionallyBridgeFromObjectiveC(_ input: NSDecimalNumber, result: inout Decimal?) -> Bool {
result = input.decimalValue
return true
}
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSDecimalNumber?) -> Decimal {
var result: Decimal?
_forceBridgeFromObjectiveC(source!, result: &result)
return result!
}
}