//===--- Integers.swift.gyb -----------------------------------*- 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 // //===----------------------------------------------------------------------===// // RUN: rm -rf %t ; mkdir -p %t // RUN: %gyb -DWORD_BITS=%target-ptrsize %s -o %t/Integers.swift // RUN: %line-directive %t/Integers.swift -- %target-build-swift %t/Integers.swift -swift-version 4 -Onone -o %t/a.out // RUN: %line-directive %t/Integers.swift -- %target-run %t/a.out // REQUIRES: executable_test // FIXME: this test runs forever on iOS arm64 // REQUIRES: OS=macosx %{ word_bits = int(WORD_BITS) / 2 from SwiftIntTypes import all_integer_types }% /// Prints the message if the body is uncommented; used for /// diagnostics. @_transparent public func _log(_ message: @autoclosure () -> String) { // print(message()) } extension FixedWidthInteger { @discardableResult // @_transparent public mutating func replaceUWord(_ n: Int, with newBits: UInt) -> Bool { let flippedBits = _word(at: n) ^ newBits self ^= Self(_truncatingBits: flippedBits) << (${word_bits} * n) if _word(at: n) != newBits { _log("###### overflow replacing word \(n) with \(newBits.hex)") } return _word(at: n) == newBits } /// a hex representation of every bit in the number func hexBits(_ bitWidth: Int) -> String { let hexDigits: [Unicode.Scalar] = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"] var result = "".unicodeScalars var x = self var nibbles: Int = 0 repeat { if nibbles % 4 == 0 && nibbles != 0 { result.insert("_", at: result.startIndex) } let lowUWord = x._word(at: 0) result.insert( hexDigits[Int(lowUWord._value) & 0xF], at: result.startIndex ) x.replaceUWord(0, with: lowUWord & ~0xF) x /= 16 nibbles += 1 } while (nibbles << 2 < bitWidth || (x != 0 && x + 1 != 0)) return (self < 0 ? "[-]" : "[+]") + String(result) } var hex: String { return hexBits(0) } } typealias Word = Int${word_bits} typealias UWord = UInt${word_bits} typealias DWord = Int${word_bits*2} typealias UDWord = UInt${word_bits*2} import StdlibUnittest func expectEqual( _ expected: T, _ actual: T, _ message: @autoclosure () -> String = "", stackTrace: SourceLocStack = SourceLocStack(), showFrame: Bool = true, file: String = #file, line: UInt = #line ) { if expected != actual { expectationFailure( "expected: \(String(reflecting: expected))" + " (of type \(String(reflecting: type(of: expected))))\n" + " = \(expected.hex)\n" + "actual: \(String(reflecting: actual))" + " (of type \(String(reflecting: type(of: actual))))\n" + " = \(actual.hex)\n", trace: message(), stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)) } } func expectEqual( _ expected: (T, ArithmeticOverflow), _ actual: (T, ArithmeticOverflow), _ message: @autoclosure () -> String = "", stackTrace: SourceLocStack = SourceLocStack(), showFrame: Bool = true, file: String = #file, line: UInt = #line ) { % for i in 0, 1: expectEqual( expected.${i}, actual.${i}, message(), stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false) % end } var tests = TestSuite("Integers") tests.test("Literals") { // Testing against the official Int types so as not to depend on // unimplemented stuff. let a: UInt8 = 0b1_0_11_0_111 expectEqual(a, 0b1_0_11_0_111) let b: Int16 = 183 expectEqual(b, 0b1_0_11_0_111) let c: Int16 = -183 expectEqual(c, -183) let d: Int8 = 127 expectEqual(d, 127) let e: UInt8 = 255 expectEqual(e, 255) } tests.test("Equality") { expectEqual(183 as UInt8, 183) expectNotEqual(183 as UInt8, 184) expectEqual(49 as Int8, 49) expectNotEqual(-49 as Int8, 49) } func indexOrder(x: T, y: T) -> ExpectedComparisonResult { return x < y ? .lt : x > y ? .gt : .eq } tests.test("Ordering") { checkComparable([127, 183, 184, 255] as [UInt8], oracle: indexOrder) checkComparable([-128, -1, 83, 84, 127] as [Int8], oracle: indexOrder) checkComparable([127, 183, 184, 255, 65535] as [UInt16], oracle: indexOrder) checkComparable([-32768, -32767, 83, 84, 32767] as [Int16], oracle: indexOrder) } tests.test("Simple-Arithmetic") { expectEqual(1 as Int8 + 2, 3) expectEqual(1 as Int8 - 2, -1) expectEqual(-5 as Int8 + 11, 6) expectEqual(3 as Int8 * 4, 12) expectEqual(4 as Int8 * -7, -28) expectEqual(-4 as Int8 * -7, 28) expectEqual(5 as Int8 / 2, 2) expectEqual(6 as Int8 / 2, 3) expectEqual(7 as Int8 / 2, 3) expectEqual(5 as Int8 % 3, 2) expectEqual(6 as Int8 % 3, 0) expectEqual(7 as Int8 % 3, 1) } % for w in map(lambda x: x.bits, all_integer_types(word_bits)): % for prefix in ['U', '']: % Type = '{}Int{}'.format(prefix, w) tests.test("${Type}/Add/Overflow") { func f(_ x: ${Type}) -> ${Type} { return x + 1 } expectCrashLater() _ = f(${Type}.max) } tests.test("${Type}/Subtract/Underflow") { func f(_ x: ${Type}) -> ${Type} { return x - 1 } expectCrashLater() _ = f(${Type}.min) } tests.test("${Type}/AddInPlace/Overflow") { func f(_ x: inout ${Type}) { x += 1 } expectCrashLater() var x = ${Type}.max f(&x) } tests.test("${Type}/SubtractInPlace/Underflow") { func f(_ x: inout ${Type}) { x -= 1 } expectCrashLater() var x = ${Type}.min f(&x) } % end % end tests.test("Simple-Bitwise") { expectEqual(0b100_1001 as Int8 >> 1, 0b10_0100) expectEqual(-0b100_1001 as Int8 >> 1, -0b10_0101) expectEqual(0b1011_0111 as UInt8 >> 1, 0b0101_1011) expectEqual(0b100_1001 as Int8 >> 1, 0b10_0100) expectEqual(-0b100_1001 as Int8 >> 1, -0b10_0101) expectEqual(0b1011_0111 as UInt8 >> 1, 0b0101_1011) expectEqual((0b1011_0111 as UInt8) & 0b0110_1110, 0b0010_0110) expectEqual((0b1011_0111 as UInt8) | 0b0110_1110, 0xFF) expectEqual((0b1011_0111 as UInt8) ^ 0b0110_1110, 0b1101_1001) } tests.test("MinMax") { expectEqual(255, UInt8.max) expectEqual(0, UInt8.min) expectEqual(127, Int8.max) expectEqual(-128, Int8.min) } tests.test("CountLeadingZeros") { expectEqual(0, UInt8.max.leadingZeroBitCount) expectEqual(8, UInt8.min.leadingZeroBitCount) expectEqual(1, Int8.max.leadingZeroBitCount) expectEqual(0, Int8.min.leadingZeroBitCount) } tests.test("CountTrainlingZeros") { expectEqual(0, UInt8.max.trailingZeroBitCount) expectEqual(8, UInt8.min.trailingZeroBitCount) expectEqual(0, Int8.max.trailingZeroBitCount) expectEqual(7, Int8.min.trailingZeroBitCount) } tests.test("Conversion8to16") { expectEqual(255, UInt16(UInt8.max)) expectEqual(255, Int16(UInt8.max)) expectEqual(0, UInt16(UInt8.min)) expectEqual(0, Int16(UInt8.min)) expectEqual(127, Int16(Int8.max)) let negativeValue = Int8.min expectCrashLater() _ = UInt16(negativeValue) } tests.test("Conversion16to8") { expectEqual(255, UInt8(255 as UInt16)) expectEqual(255, UInt8(255 as Int16)) expectEqual(0, UInt8(0 as UInt16)) expectEqual(0, UInt8(0 as Int16)) expectEqual(127, Int8(127 as UInt16)) expectEqual(127, Int8(127 as Int16)) expectEqual(-128, Int8(-128 as Int16)) let tooLarge: UInt16 = 128 expectCrashLater() _ = Int8(tooLarge) } tests.test("Conversion16to8a") { let tooLarge: Int16 = 128 expectCrashLater() _ = Int8(tooLarge) } tests.test("Conversion16to8b") { let tooLarge: Int16 = 256 expectCrashLater() _ = UInt8(tooLarge) } tests.test("Conversion16to8c") { let tooLarge: UInt16 = 256 expectCrashLater() _ = UInt8(tooLarge) } tests.test("ConversionWordToDWord") { expectEqual(1 << ${word_bits} - 1, UDWord(UWord.max)) expectEqual(1 << ${word_bits} - 1, DWord(UWord.max)) expectEqual(0, UDWord(UWord.min)) expectEqual(0, DWord(UWord.min)) expectEqual(1 << ${word_bits-1} - 1, DWord(Word.max)) let negativeValue = Word.min expectCrashLater() _ = UDWord(negativeValue) } tests.test("ConversionDWordToWord") { expectEqual(~0, UWord(1 << ${word_bits} - 1 as UDWord)) expectEqual(~0, UWord(1 << ${word_bits} - 1 as DWord)) expectEqual(0, UWord(0 as UDWord)) expectEqual(0, UWord(0 as DWord)) expectEqual(Word.max, Word(1 << ${word_bits-1} - 1 as UDWord)) expectEqual(Word.max, Word(1 << ${word_bits-1} - 1 as DWord)) expectEqual(Word.min, Word(-1 << ${word_bits-1} as DWord)) let tooLarge: UDWord = 1 << ${word_bits-1} expectCrashLater() _ = Word(tooLarge) } tests.test("ConversionDWordToWordA") { let tooLarge: DWord = 1 << ${word_bits} expectCrashLater() _ = Word(tooLarge) } tests.test("ConversionDWordToWordB") { let tooLarge: DWord = 1 << ${word_bits} expectCrashLater() _ = UWord(tooLarge) } tests.test("ConversionDWordToWordC") { let tooLarge: UDWord = 1 << ${word_bits} expectCrashLater() _ = UWord(tooLarge) } tests.test("extendingOrTruncating") { expectEqual(-2, Int8(extendingOrTruncating: UInt8.max - 1)) expectEqual(3, Int8(extendingOrTruncating: 3 as UInt8)) expectEqual(UInt8.max - 1, UInt8(extendingOrTruncating: -2 as Int8)) expectEqual(3, UInt8(extendingOrTruncating: 3 as Int8)) expectEqual(-2, DWord(extendingOrTruncating: UDWord.max - 1)) expectEqual(3, DWord(extendingOrTruncating: 3 as UDWord)) expectEqual(UDWord.max - 1, UDWord(extendingOrTruncating: -2 as DWord)) expectEqual(3, UDWord(extendingOrTruncating: 3 as DWord)) expectEqual(-2, Int32(extendingOrTruncating: -2 as Int8)) expectEqual(3, Int32(extendingOrTruncating: 3 as Int8)) expectEqual(127, Int32(extendingOrTruncating: 127 as UInt8)) expectEqual(129, Int32(extendingOrTruncating: 129 as UInt8)) expectEqual((1 << 31 - 1) << 1, UInt32(extendingOrTruncating: -2 as Int8)) expectEqual(3, UInt32(extendingOrTruncating: 3 as Int8)) expectEqual(128, UInt32(extendingOrTruncating: 128 as UInt8)) expectEqual(129, UInt32(extendingOrTruncating: 129 as UInt8)) expectEqual(-2, DWord(extendingOrTruncating: -2 as Int8)) expectEqual(3, DWord(extendingOrTruncating: 3 as Int8)) expectEqual(127, DWord(extendingOrTruncating: 127 as UInt8)) expectEqual(129, DWord(extendingOrTruncating: 129 as UInt8)) expectEqual( (1 << ${word_bits*2-1} - 1) << 1, UDWord(extendingOrTruncating: -2 as Int8)) expectEqual(3, UDWord(extendingOrTruncating: 3 as Int8)) expectEqual(128, UDWord(extendingOrTruncating: 128 as UInt8)) expectEqual(129, UDWord(extendingOrTruncating: 129 as UInt8)) expectEqual(-2, Int8(extendingOrTruncating: -2 as DWord)) expectEqual(-2, Int8(extendingOrTruncating: -1 << 67 - 2 as DWord)) expectEqual(127, Int8(extendingOrTruncating: 127 as UDWord)) expectEqual(-127, Int8(extendingOrTruncating: 129 as UDWord)) expectEqual(0b1111_1100, UInt8(extendingOrTruncating: -4 as DWord)) expectEqual(0b1111_1100, UInt8(extendingOrTruncating: -1 << 67 - 4 as DWord)) expectEqual(128, UInt8(extendingOrTruncating: 128 + 1024 as UDWord)) expectEqual(129, UInt8(extendingOrTruncating: 129 + 1024 as UDWord)) } tests.test("HeterogeneousEquality") { expectTrue(-1 as DWord != UDWord.max) expectTrue(DWord.max == UDWord.max / 2) expectTrue((0 as DWord) == 0 as UDWord) expectTrue(-1 as Int8 == -1 as DWord) expectTrue(UInt8.max != -1 as DWord) expectTrue(UInt8.max == 255 as DWord) expectTrue((0 as UInt8) == 0 as DWord) expectTrue(UInt8.max == 255 as UDWord) expectTrue(UInt8.max != UDWord.max) expectTrue((0 as UInt8) == (0 as UDWord)) } tests.test("HeterogeneousOrdering") { expectTrue((-1 as DWord) < UDWord.max) expectTrue(DWord.max <= UDWord.max / 2) expectTrue(DWord.max >= UDWord.max / 2) expectTrue((0 as DWord) <= (0 as UDWord)) expectTrue((0 as DWord) >= (0 as UDWord)) expectTrue((-1 as Int8) <= -1 as DWord) expectTrue((-1 as Int8) >= -1 as DWord) expectTrue(UInt8.max > -1 as DWord) expectTrue(UInt8.max <= 255 as DWord) expectTrue(UInt8.max >= 255 as DWord) expectTrue((0 as UInt8) <= (0 as DWord)) expectTrue((0 as UInt8) >= (0 as DWord)) expectTrue(UInt8.max <= 255 as UDWord) expectTrue(UInt8.max >= 255 as UDWord) expectTrue(UInt8.max < UDWord.max) expectTrue((0 as UInt8) <= (0 as UDWord)) expectTrue((0 as UInt8) >= (0 as UDWord)) } tests.test("SmartBitShift/Homogeneous/Left/Int16") { let all1s = ~0 as Int16 expectEqual(all1s, all1s << (0 as Int16)) expectEqual(-2, all1s << (1 as Int16)) expectEqual(Int16.min, all1s << (15 as Int16)) expectEqual(0, all1s << (16 as Int16)) expectEqual(-1, all1s << (-1 as Int16)) expectEqual(-1, all1s << (-15 as Int16)) expectEqual(-1, all1s << (-16 as Int16)) } tests.test("SmartBitShift/Unconstrained/Left/Int16") { let all1s = ~0 as Int16 expectEqual(all1s, all1s << 0) expectEqual(-2, all1s << 1) expectEqual(Int16.min, all1s << 15) expectEqual(0, all1s << 16) expectEqual(-1, all1s << -1) expectEqual(-1, all1s << -15) expectEqual(-1, all1s << -16) } tests.test("SmartBitShift/Homogeneous/Left/UInt16") { let all1s = ~0 as UInt16 expectEqual(all1s, all1s << 0) expectEqual(0b1111_1111_1111_1110, all1s << 1) expectEqual(UInt16.max / 2 + 1, all1s << 15) expectEqual(0, all1s << 16) } tests.test("SmartBitShift/Heterogeneous/Left/Int16") { let all1s = ~0 as Int16 expectEqual(all1s, all1s << (0 as Int8)) expectEqual(-2, all1s << (1 as Int32)) expectEqual(Int16.min, all1s << (15 as UInt32)) expectEqual(0, all1s << (16 as UInt8)) expectEqual(-1, all1s << (-1 as DWord)) expectEqual(-1, all1s << (-15 as Int)) expectEqual(-1, all1s << (-16 as Int32)) } tests.test("SmartBitShift/Heterogeneous/Left/UInt16") { let all1s = ~0 as UInt16 expectEqual(all1s, all1s << (0 as Int8)) expectEqual(0b1111_1111_1111_1110, all1s << (1 as Int32)) expectEqual(UInt16.max / 2 + 1, all1s << (15 as UInt32)) expectEqual(0, all1s << (16 as UInt8)) expectEqual(UInt16.max / 2, all1s << (-1 as DWord)) expectEqual(1, all1s << (-15 as Int)) expectEqual(0, all1s << (-16 as Int32)) } tests.test("SmartBitShift/Unconstrained/Left/UInt16") { let all1s = ~0 as UInt16 expectEqual(all1s, all1s << 0) expectEqual(0b1111_1111_1111_1110, all1s << 1) expectEqual(UInt16.max / 2 + 1, all1s << 15) expectEqual(0, all1s << 16) expectEqual(UInt16.max / 2, all1s << -1) expectEqual(1, all1s << -15) expectEqual(0, all1s << -16) } tests.test("Basics") { typealias I8 = UInt8 let b8: I8 = 0b1_0_11_0_111 expectEqual(b8, 0b1_0_11_0_111) expectEqual(b8, 183) expectNotEqual(b8, I8()) expectEqual(I8(), 0) expectEqual(8, I8.bitWidth) expectEqual(16, Int16.bitWidth) expectEqual(32, Int32.bitWidth) } tests.test("word") { let x = UDWord(Int.max) expectEqual(Int.max._lowUWord, x._word(at: 0)) expectEqual(0, x._word(at: 1)) let y = DWord(Int.min) expectEqual(Int.min._lowUWord, y._word(at: 0)) expectEqual(~0, y._word(at: 1)) let z = UInt(~Int.min) + 1 expectEqual(Int.min._lowUWord, z._word(at: 0)) expectEqual(0, z._word(at: 1)) } tests.test("words") { expectEqualSequence([UInt.max], (-1 as Int).words) expectEqualSequence([UInt.max], (-1 as Int8).words) expectEqualSequence([UInt.max], (-1 as Int16).words) expectEqualSequence([UInt.max], (-1 as Int32).words) expectEqualSequence([UInt.max], (-1 as Int64).words) expectEqualSequence([1], 1.words) expectEqualSequence([0], 0.words) } tests.test("multipliedFullWidth/UInt8") { let a: UInt8 = 42 let b: UInt8 = 42 let res = a.multipliedFullWidth(by: b) expectEqual(0x06, res.high) expectEqual(0xe4, res.low) } tests.test("multipliedFullWidth/Int8") { let a: Int8 = 42 let b: Int8 = -42 let res = a.multipliedFullWidth(by: b) expectEqual(Int8(bitPattern: 0xf9), res.high) expectEqual(0x1c, res.low) } tests.test("multipliedFullWidth/Int8/BothNegative") { let a: Int8 = -42 let b: Int8 = -42 let res = a.multipliedFullWidth(by: b) expectEqual(0x06, res.high) expectEqual(0xe4, res.low) } tests.test("MultiplyAndDivideFullWidth/Int8") { let a: Int8 = 42 let b: Int8 = 43 let res = a.multipliedFullWidth(by: b) let (quotient, remainder) = b.dividingFullWidth(res) expectEqual(a, quotient) expectEqual(0, remainder) } tests.test("Remainder/DividingBy0") { func f(_ x: Int, _ y: Int) -> Int { return x % y } expectCrashLater() _ = f(42, 0) } tests.test("Division/By0") { func f(_ x: Int, _ y: Int) -> Int { return x / y } expectCrashLater() _ = f(42, 0) } tests.test("DivideMinByMinusOne") { func f(_ x: Int) -> Int { return x / -1 } expectCrashLater() _ = f(Int.min) } tests.test("MultiplyMinByMinusOne") { func f(_ x: Int) -> Int { return x * -1 } expectCrashLater() _ = f(Int.min) } tests.test("signum/generic") { func check(_ expected: T, _ x: T) { expectEqual(expected, x.signum()) } % for suffix in ['8', '16', '32', '64', '']: check(-1, Int${suffix}.min) check(-1, (-42) as Int${suffix}) check(-1, (-1) as Int${suffix}) % for u in ['U', '']: check(0, 0 as ${u}Int${suffix}) check(1, 1 as ${u}Int${suffix}) check(1, 42 as ${u}Int${suffix}) check(1, ${u}Int${suffix}.max) % end % end } tests.test("signum/concrete") { % for suffix in ['8', '16', '32', '64', '']: expectEqual(-1 as Int${suffix}, Int${suffix}.min.signum()) expectEqual(-1 as Int${suffix}, (-42 as Int${suffix}).signum()) expectEqual(-1 as Int${suffix}, (-1 as Int${suffix}).signum()) % for u in ['U', '']: expectEqual(0 as ${u}Int${suffix}, (0 as ${u}Int${suffix}).signum()) expectEqual(1 as ${u}Int${suffix}, (1 as ${u}Int${suffix}).signum()) expectEqual(1 as ${u}Int${suffix}, (42 as ${u}Int${suffix}).signum()) expectEqual(1 as ${u}Int${suffix}, ${u}Int${suffix}.max.signum()) % end % end } var dwTests = TestSuite("DoubleWidth") dwTests.test("Literals") { let w: DoubleWidth = 100 expectTrue(w == 100 as Int) let x: DoubleWidth = 1000 expectTrue(x == 1000 as Int) let y: DoubleWidth = 1000 expectTrue(y == 1000 as Int) let z: DoubleWidth = -1000 expectTrue(z == -1000 as Int) } dwTests.test("Arithmetic/unsigned") { let x: DoubleWidth = 1000 let y: DoubleWidth = 1111 expectTrue(x + 1 == 1001) expectTrue(x + x == 2000) expectTrue(x - 1 == 999) expectTrue(x - x == 0) expectTrue(y - x == 111) expectTrue(x * 7 == 7000) expectTrue(y * 7 == 7777) expectTrue(x / 3 == 333) expectTrue(x / x == 1) expectTrue(x / y == 0) expectTrue(y / x == 1) expectTrue(x % 3 == 1) expectTrue(x % y == x) } dwTests.test("Arithmetic/signed") { let x: DoubleWidth = 1000 let y: DoubleWidth = -1111 expectTrue(x + 1 == 1001) expectTrue(x + x == 2000) expectTrue(x - 1 == 999) expectTrue(x - x == 0) expectTrue(0 - x == -1000) expectTrue(x + y == -111) expectTrue(x - y == 2111) expectTrue(x * 7 == 7000) expectTrue(y * 7 == -7777) expectTrue(x * -7 == -7000) expectTrue(y * -7 == 7777) expectTrue(x / 3 == 333) expectTrue(x / x == 1) expectTrue(x / y == 0) expectTrue(y / x == -1) expectTrue(x % 3 == 1) expectTrue(y % 3 == -1) expectTrue(-y == 1111) expectTrue(-x == -1000) } dwTests.test("Nested") { typealias UInt128 = DoubleWidth typealias UInt256 = DoubleWidth typealias UInt512 = DoubleWidth typealias UInt1024 = DoubleWidth do { let x = UInt1024.max let (y, o) = x.addingReportingOverflow(1) expectEqual(y, 0) expectTrue(y == (0 as Int)) expectTrue(o == .overflow) } typealias Int128 = DoubleWidth typealias Int256 = DoubleWidth typealias Int512 = DoubleWidth typealias Int1024 = DoubleWidth do { let x = Int1024.max let (y, o) = x.addingReportingOverflow(1) expectEqual(y, Int1024.min) expectLT(y, 0) expectTrue(y < (0 as Int)) expectTrue(o == .overflow) } expectFalse(UInt1024.isSigned) expectEqual(UInt1024.bitWidth, 1024) expectTrue(Int1024.isSigned) expectEqual(Int1024.bitWidth, 1024) } // FIXME: Need more tests of DoubleWidth runAllTests()