//===--- Integers.swift.gyb -----------------------------------*- swift -*-===// // // 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 https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// %{ # # Utility code for later in this template # from string import maketrans, capitalize # Number of bits in the Builtin.Word type word_bits = int(CMAKE_SIZEOF_VOID_P) * 8 # Number of bits in integer literals. builtinIntLiteralBits = 2048 IntLiteral = 'Int%s' % builtinIntLiteralBits class struct(object): def __init__(self, **kw): self.__dict__ = kw def __repr__(self): return 'struct(%r)' % self.__dict__ binaryArithmetic = { 'Arithmetic' : [ struct(operator='+', name='adding', mutatingName='add', firstArg='_', llvmName='add', kind='+'), struct(operator='-', name='subtracting', mutatingName='subtract', firstArg='_', llvmName='sub', kind='-'), struct(operator='*', name='multiplied', mutatingName='multiply', firstArg='by', llvmName='mul', kind='*'), struct(operator='/', name='divided', mutatingName='divide', firstArg='by', llvmName='div', kind='/'), ], 'BinaryInteger' : [ struct(operator='%', name='remainder', mutatingName='formRemainder', firstArg='dividingBy', llvmName='rem', kind='/'), ], } binaryBitwise = [ struct(operator='&', name='bitwiseAnd', llvmName='and'), struct(operator='|', name='bitwiseOr', llvmName='or'), struct(operator='^', name='bitwiseXor', llvmName='xor'), ] maskingShifts = [ struct( operator='&>>', nonMaskingOperator='>>', description='right shift', name='maskingShiftRight', llvmName=lambda s:['lshr','ashr'][s]), struct( operator='&<<', nonMaskingOperator='<<', description='left shift', name='maskingShiftLeft', llvmName=lambda _: 'shl'), ] }% infix operator &<< : BitwiseShiftPrecedence infix operator &<<= : AssignmentPrecedence infix operator &>> : BitwiseShiftPrecedence infix operator &>>= : AssignmentPrecedence //===----------------------------------------------------------------------===// //===--- Bits for the Stdlib ----------------------------------------------===// //===----------------------------------------------------------------------===// // FIXME(integers): This should go in the stdlib separately, probably. extension ExpressibleByIntegerLiteral where Self : _ExpressibleByBuiltinIntegerLiteral { /// Create an instance initialized to `value`. @_transparent public init(integerLiteral value: Self) { self = value } } //===----------------------------------------------------------------------===// //===--- Arithmetic -------------------------------------------------------===// //===----------------------------------------------------------------------===// /// Declares methods backing binary arithmetic operators—such as `+`, `-` and /// `*`—and their mutating counterparts. /// /// It provides a suitable basis for arithmetic on scalars such as integers and /// floating point numbers. /// /// Both mutating and non-mutating operations are declared in the protocol, /// however only the mutating ones are required, as default implementations of /// the non-mutating ones are provided by a protocol extension. /// /// The `Magnitude` associated type is able to hold the absolute value of any /// possible value of `Self`. Concrete types do not have to provide a typealias /// for it, as it can be inferred from the `magnitude` property. This property /// can be useful in operations that are simpler to implement in terms of /// unsigned values, for example, printing a value of an integer, which is just /// printing a '-' character in front of an absolute value. /// /// Please note that for ordinary work, the `magnitude` property **should not** /// be preferred to the `abs(_)` function, whose return value is of the same /// type as its argument. public protocol Arithmetic : Equatable, ExpressibleByIntegerLiteral { // FIXME(integers): implement //init?(exactly source: T) // FIXME(ABI)#44 (Recursive Protocol Constraints): should be just Arithmetic associatedtype Magnitude : Equatable, ExpressibleByIntegerLiteral var magnitude: Magnitude { get } % for x in binaryArithmetic['Arithmetic']: // defaulted using an in-place counterpart, but can be used as an // optimization hook func ${x.name}(${x.firstArg} rhs: Self) -> Self // implementation hook mutating func ${x.mutatingName}(${x.firstArg} rhs: Self) % end } extension Arithmetic { @_transparent public init() { self = 0 } } % for Protocol in binaryArithmetic: extension ${Protocol} { % for x in binaryArithmetic[Protocol]: % callLabel = x.firstArg + ': ' if not x.firstArg == '_' else '' public func ${x.name}(${x.firstArg} rhs: Self) -> Self { var lhs = self lhs.${x.mutatingName}(${callLabel}rhs) return lhs } % end } % end public protocol SignedArithmetic : Arithmetic { func negated() -> Self mutating func negate() } extension SignedArithmetic { public func negated() -> Self { return Self().subtracting(self) } public mutating func negate() { self = negated() } } //===----------------------------------------------------------------------===// //===--- Arithmetic operators ---------------------------------------------===// //===----------------------------------------------------------------------===// % for Protocol in binaryArithmetic: % for x in binaryArithmetic[Protocol]: % callLabel = x.firstArg + ': ' if not x.firstArg == '_' else '' @_transparent public func ${x.operator} (lhs: T, rhs: T) -> T { return lhs.${x.name}(${callLabel}rhs) } @_transparent public func ${x.operator}= (lhs: inout T, rhs: T) { lhs.${x.mutatingName}(${callLabel}rhs) } % end % end @_transparent public prefix func - (x: T) -> T { return x.negated() } //===----------------------------------------------------------------------===// //===--- BinaryInteger ----------------------------------------------------===// //===----------------------------------------------------------------------===// public protocol BinaryInteger : Comparable, Arithmetic, CustomStringConvertible { static var isSigned: Bool { get } // Dispatching through these puts less stress on the user reading // the interface and error messages (and on the type checker) than // does having many operator overloads. func isEqual(to rhs: Self) -> Bool func isLess(than rhs: Self) -> Bool init?(exactly source: T) init(_ source: T) init(_ source: T) init(extendingOrTruncating source: T) init(clamping source: T) func word(at n: Int) -> UInt var bitWidth : Int { get } var minimumSignedRepresentationBitWidth: Int { get } % for x in binaryArithmetic['BinaryInteger']: // defaulted using an in-place counterpart, but can be used as an // optimization hook func ${x.name}(${x.firstArg} rhs: Self) -> Self // implementation hook mutating func ${x.mutatingName}(${x.firstArg} rhs: Self) % end func quotientAndRemainder(dividingBy rhs: Self) -> (Self, Self) /// Returns `-1` if the value of `self` is negative, `1` if it's positive, /// `0` otherwise. func signum() -> Self } extension BinaryInteger { public init?(exactly source: T) { // FIXME(integers): implement fatalError() return nil } public init(_ source: T) { // FIXME(integers): implement fatalError() } public func signum() -> Self { // FIXME(integers): implement fatalError() } public var countRepresentedWords: Int { return (self.bitWidth + ${word_bits} - 1) / ${word_bits} } public func quotientAndRemainder(dividingBy rhs: Self) -> (Self, Self) { return (self.divided(by: rhs), self.remainder(dividingBy: rhs)) } } //===----------------------------------------------------------------------===// //===--- Homogeneous comparison -------------------------------------------===// //===----------------------------------------------------------------------===// @_transparent public func == (lhs: T, rhs: T) -> Bool { return lhs.isEqual(to: rhs) } @_transparent public func < (lhs: T, rhs: T) -> Bool { return lhs.isLess(than: rhs) } //===----------------------------------------------------------------------===// //===--- Heterogeneous comparison -----------------------------------------===// //===----------------------------------------------------------------------===// @_transparent public func == (lhs: T, rhs: U) -> Bool { return (lhs > 0) == (rhs > 0) && T(extendingOrTruncating: rhs) == lhs && U(extendingOrTruncating: lhs) == rhs } @_transparent public func != (lhs:T, rhs: U) -> Bool { return !(lhs == rhs) } @_transparent public func < (lhs: T, rhs: U) -> Bool { let lhsSign = lhs < 0 ? -1 : lhs > 0 ? 1 : 0 let rhsSign = rhs < 0 ? -1 : rhs > 0 ? 1 : 0 if lhsSign != rhsSign { return lhsSign < rhsSign } // if we get here, lhs and rhs have the same sign. If they're // negative, then T and U are both signed types, and one of them can // represent values of the other type. Otherwise, lhs and rhs are // positive, and one of T, U may be signed and the other unsigned. // In this case, we can conceptually subtract 1 from the bitWidth of // any signed type, and either the resulting bitWidths are the same // or one can represent every value of the other. let rT = T(extendingOrTruncating: rhs) // Can we round-trip rhs through T? if U(extendingOrTruncating: rT) == rhs { return lhs < rT } return U(extendingOrTruncating: lhs) < rhs } @inline(__always) public func <= (lhs: T, rhs: U) -> Bool { return !(rhs < lhs) } @inline(__always) public func >= (lhs: T, rhs: U) -> Bool { return !(lhs < rhs) } @inline(__always) public func > (lhs: T, rhs: U) -> Bool { return rhs < lhs } //===----------------------------------------------------------------------===// //===--- Ambiguity breakers -----------------------------------------------===// // These two versions of the operators are not ordered with respect to // one another: // // (T, T) -> Bool // (T, U) -> Bool // // so we define: // // (T, T) -> Bool //===----------------------------------------------------------------------===// @_transparent public func != (lhs: T, rhs: T) -> Bool { return !(lhs == rhs) } @inline(__always) public func <= (lhs: T, rhs: T) -> Bool { return !(rhs < lhs) } @inline(__always) public func >= (lhs: T, rhs: T) -> Bool { return !(lhs < rhs) } @inline(__always) public func > (lhs: T, rhs: T) -> Bool { return rhs < lhs } //===----------------------------------------------------------------------===// //===--- FixedWidthInteger ------------------------------------------------===// //===----------------------------------------------------------------------===// public enum ArithmeticOverflow { @_transparent public init(_ overflow: Bool) { self = overflow ? .overflow : .none } case none, overflow } public protocol FixedWidthInteger : BinaryInteger { static var bitWidth : Int { get } static var max: Self { get } static var min: Self { get } % for x in binaryArithmetic['Arithmetic']: %{ comment = ''' /// Return a pair consisting of `self` {} `rhs`, /// truncated to fit if necessary, and a flag indicating whether an /// arithmetic overflow occurred.'''.format(x.operator) + (''' /// /// - Precondition: `rhs != 0`''' if x.kind == '/' else '') }% ${comment} func ${x.name}WithOverflow( ${x.firstArg} rhs: Self ) -> (partialValue: Self, overflow: ArithmeticOverflow) % end % for x in binaryBitwise + maskingShifts: func ${x.name}(_ rhs: Self) -> Self % end static func doubleWidthMultiply(_ lhs: Self, _ rhs: Self) -> (high: Self, low: Magnitude) static func doubleWidthDivide( _ lhs: (high: Self, low: Magnitude), _ rhs: Self) -> (quotient: Self, remainder: Self) init(_truncatingBits bits: UInt) var popcount: Int { get } var leadingZeros: Int { get } } //===----------------------------------------------------------------------===// //===--- Operators on FixedWidthInteger -----------------------------------===// //===----------------------------------------------------------------------===// @inline(__always) public prefix func ~ (x: T) -> T { return 0 &- x &- 1 } % for x in binaryBitwise: @_transparent public func ${x.operator} (lhs: T, rhs: T) -> T { return lhs.${x.name}(rhs) } @_transparent public func ${x.operator}= (lhs: inout T, rhs: T) { lhs = lhs.${x.name}(rhs) } % end % for x in maskingShifts: @_transparent public func ${x.operator} (lhs: T, rhs: T) -> T { return lhs.${x.name}(rhs) } @_transparent public func ${x.operator}= (lhs: inout T, rhs: T) { lhs = lhs ${x.operator} rhs } @_transparent public func ${x.operator} < T: FixedWidthInteger, U: BinaryInteger >(lhs: T, rhs: U) -> T { return lhs.${x.name}(T(extendingOrTruncating: rhs)) } @_transparent public func ${x.operator}= < T: FixedWidthInteger, U: BinaryInteger >(lhs: inout T, rhs: U) { lhs = lhs ${x.operator} rhs } @_transparent public func ${x.nonMaskingOperator} < T: FixedWidthInteger, U: BinaryInteger >(lhs: T, rhs: U) -> T { // FIXME(integers): uncomment once Int conforms to BinaryInteger //let shift = rhs < -T.bitWidth ? -T.bitWidth //: rhs > T.bitWidth ? T.bitWidth //: Int(rhs) //return lhs ${x.nonMaskingOperator} shift fatalError() } //===----------------------------------------------------------------------===// //=== "Smart ${x.description}", supporting overshifts and negative shifts -===// //===----------------------------------------------------------------------===// @_transparent public func ${x.nonMaskingOperator} < T: FixedWidthInteger >(lhs: T, rhs: Int) -> T { // FIXME(integers): uncomment once Int conforms to BinaryInteger fatalError() //let overshiftR = T.isSigned ? lhs &>> (T.bitWidth - 1) : 0 //let overshiftL: T = 0 //if _fastPath(rhs >= 0) { //if _fastPath(rhs < T.bitWidth) { //return lhs.${x.name}(T(extendingOrTruncating: rhs)) //} //return overshift${'LR'['R' in x.name]} //} //if _slowPath(rhs <= -T.bitWidth) { //return overshift${'RL'['R' in x.name]} //} //return lhs ${x.operator.translate(maketrans('<>', '><'))} -rhs } @_transparent public func ${x.nonMaskingOperator}= < T: FixedWidthInteger >(lhs: inout T, rhs: T) { lhs = lhs ${x.nonMaskingOperator} rhs } @_transparent public func ${x.nonMaskingOperator}= < T: FixedWidthInteger, U: BinaryInteger >(lhs: inout T, rhs: U) { lhs = lhs ${x.nonMaskingOperator} rhs } % end # maskingShifts extension FixedWidthInteger { public init(clamping source: Other) { if _slowPath(source < Self.min) { self = Self.min } else if _slowPath(source > Self.max) { self = Self.max } else { self = Self(extendingOrTruncating: source) } } % for x in binaryArithmetic['Arithmetic']: % callLabel = x.firstArg + ': ' if not x.firstArg == '_' else '' @_transparent // FIXME(integers): rename `rhs` to `other` public mutating func ${x.mutatingName}(${x.firstArg} rhs: Self) { let (result, _ /*overflow*/) = self.${x.name}WithOverflow(${callLabel}rhs) // FIXME(integers): overflow check //_assertCond(overflow == .none, "overflow in ${x.name}") self = result } /// Return `self ${x.operator} rhs`. If an arithmetic overflow /// occurs, the behavior is undefined. /// /// Note: use this function to avoid the cost of overflow checking /// when you are sure that the operation won't overflow. @_transparent public func unsafe${capitalize(x.name)}(rhs: Self) -> Self { let (result, overflow) = self.${x.name}WithOverflow(${callLabel}rhs) if (overflow != .none) { if (_isDebugAssertConfiguration()) { _preconditionFailure("overflow in unsafe${capitalize(x.name)}") } else { Builtin.conditionallyUnreachable() } } return result } % end @_transparent public mutating func formRemainder(dividingBy other: Self) { // FIXME(integers): implement fatalError() } @_transparent public init(extendingOrTruncating source: T) { if Self.bitWidth <= ${word_bits} { self = Self.init(_truncatingBits: source.word(at: 0)) } else { var result: Self = source < 0 ? ~0 : 0 // start with the most significant word var n = source.countRepresentedWords while n >= 0 { // masking is OK here because this we have already ensured // that Self.bitWidth > ${word_bits}. Not masking results in // infinite recursion. result &<<= ${word_bits} result |= Self(_truncatingBits: source.word(at: n)) n -= 1 } self = result } } @_transparent // FIXME(integers): give it a better name. _highBitIndex is **NOT** what it is public // transparent static var _highBitIndex: Self { // FIXME(integers): uncomment once UInt conforms to BinaryInteger //return Self.init(_truncatingBits: UInt(Self.bitWidth._storage) &- 1) fatalError() } public var popcount: Int { fatalError() } public static func doubleWidthDivide( _ lhs: (high: Self, low: Magnitude), _ rhs: Self) -> (quotient: Self, remainder: Self) { fatalError() } } % for x in [op for ops in binaryArithmetic.values() for op in ops]: % callLabel = x.firstArg + ': ' if not x.firstArg == '_' else '' % if x.kind != '/': public func &${x.operator} (lhs: T, rhs: T) -> T { return lhs.${x.name}WithOverflow(${callLabel}rhs).partialValue } % end % end //===----------------------------------------------------------------------===// //===--- UnsignedInteger --------------------------------------------------===// //===----------------------------------------------------------------------===// public protocol UnsignedInteger_ : BinaryInteger { associatedtype Magnitude : BinaryInteger } extension UnsignedInteger_ { @_transparent public var magnitude: Self { return self } @_transparent public static var isSigned: Bool { return false } public var description: String { // FIXME(integers): uncomment once Int conforms to BinaryInteger fatalError() //if self == 0 { //return "0" //} //let ascii0 = 48 //var buf: [UnicodeScalar] = [] //var x = self //repeat { //let r = x % 10 //x /= 10 //buf.append( //UnicodeScalar( //ascii0 + Int(Word(extendingOrTruncating: r)._storage))) //} //while x != 0 //return String(buf.reversed().lazy.map { Character($0) }) } } extension UnsignedInteger_ where Self : FixedWidthInteger { @_transparent public init(_ source: T) { // FIXME(integers): uncomment checks //_assertCond( //source >= 0, "negative value \(source) not representable by \(Self.self)") //let requiredBits = source.minimumSignedRepresentationBitWidth - 1 //_assertCond( //requiredBits <= Self.bitWidth, //"\(Self.self) cannot store all \(requiredBits) bits " //+ "needed for unsigned representation of \(source)") self.init(extendingOrTruncating: source) } @_transparent public init?(exactly source: T) { // FIXME(integers): uncomment checks //_assertCond( //source >= 0, "negative value \(source) not representable by \(Self.self)") let requiredBits = source.minimumSignedRepresentationBitWidth - 1 if requiredBits > Self.bitWidth { return nil } self.init(extendingOrTruncating: source) } @_transparent public static var max: Self { return ~0 } @_transparent public static var min: Self { return 0 } } //===----------------------------------------------------------------------===// //===--- SignedInteger ----------------------------------------------------===// //===----------------------------------------------------------------------===// public protocol SignedInteger_ : BinaryInteger, SignedArithmetic { associatedtype Magnitude : BinaryInteger } extension SignedInteger_ { public var description: String { let base = String(describing: magnitude) return self < 0 ? "-" + base : base } @_transparent public static var isSigned: Bool { return true } } extension SignedInteger_ where Self : FixedWidthInteger { @_transparent public init(_ source: T) { // FIXME(integers): uncomment checks //let requiredBits = source.minimumSignedRepresentationBitWidth //_assertCond( //requiredBits <= Self.bitWidth, //"\(Self.self) cannot store all \(requiredBits) bits " //+ "needed for signed representation of \(source)") self.init(extendingOrTruncating: source) } @_transparent public init?(exactly source: T) { let requiredBits = source.minimumSignedRepresentationBitWidth if requiredBits > Self.bitWidth { return nil } self.init(extendingOrTruncating: source) } @_transparent public static var max: Self { return ~min } @_transparent public static var min: Self { return -1 &<< Self._highBitIndex } }