mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
900 lines
25 KiB
Swift
900 lines
25 KiB
Swift
//===--- 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 where Words : Collection {
|
|
/// 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.words.first ?? 0
|
|
result.insert(
|
|
hexDigits[Int(lowUWord._value) & 0xF],
|
|
at: result.startIndex
|
|
)
|
|
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<T : FixedWidthInteger>(
|
|
_ expected: T, _ actual: T,
|
|
_ message: @autoclosure () -> String = "",
|
|
stackTrace: SourceLocStack = SourceLocStack(),
|
|
showFrame: Bool = true,
|
|
file: String = #file, line: UInt = #line
|
|
) where T.Words : Collection {
|
|
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<T : FixedWidthInteger>(
|
|
_ expected: (T, Bool), _ actual: (T, Bool),
|
|
_ 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<T: Comparable>(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("truncatingIfNeeded") {
|
|
|
|
expectEqual(-2, Int8(truncatingIfNeeded: UInt8.max - 1))
|
|
expectEqual(3, Int8(truncatingIfNeeded: 3 as UInt8))
|
|
expectEqual(UInt8.max - 1, UInt8(truncatingIfNeeded: -2 as Int8))
|
|
expectEqual(3, UInt8(truncatingIfNeeded: 3 as Int8))
|
|
|
|
expectEqual(-2, DWord(truncatingIfNeeded: UDWord.max - 1))
|
|
expectEqual(3, DWord(truncatingIfNeeded: 3 as UDWord))
|
|
expectEqual(UDWord.max - 1, UDWord(truncatingIfNeeded: -2 as DWord))
|
|
expectEqual(3, UDWord(truncatingIfNeeded: 3 as DWord))
|
|
|
|
expectEqual(-2, Int32(truncatingIfNeeded: -2 as Int8))
|
|
expectEqual(3, Int32(truncatingIfNeeded: 3 as Int8))
|
|
expectEqual(127, Int32(truncatingIfNeeded: 127 as UInt8))
|
|
expectEqual(129, Int32(truncatingIfNeeded: 129 as UInt8))
|
|
expectEqual((1 << 31 - 1) << 1, UInt32(truncatingIfNeeded: -2 as Int8))
|
|
expectEqual(3, UInt32(truncatingIfNeeded: 3 as Int8))
|
|
expectEqual(128, UInt32(truncatingIfNeeded: 128 as UInt8))
|
|
expectEqual(129, UInt32(truncatingIfNeeded: 129 as UInt8))
|
|
|
|
expectEqual(-2, DWord(truncatingIfNeeded: -2 as Int8))
|
|
expectEqual(3, DWord(truncatingIfNeeded: 3 as Int8))
|
|
expectEqual(127, DWord(truncatingIfNeeded: 127 as UInt8))
|
|
expectEqual(129, DWord(truncatingIfNeeded: 129 as UInt8))
|
|
expectEqual(
|
|
(1 << ${word_bits*2-1} - 1) << 1,
|
|
UDWord(truncatingIfNeeded: -2 as Int8))
|
|
expectEqual(3, UDWord(truncatingIfNeeded: 3 as Int8))
|
|
expectEqual(128, UDWord(truncatingIfNeeded: 128 as UInt8))
|
|
expectEqual(129, UDWord(truncatingIfNeeded: 129 as UInt8))
|
|
|
|
expectEqual(-2, Int8(truncatingIfNeeded: -2 as DWord))
|
|
expectEqual(-2, Int8(truncatingIfNeeded: -1 << 67 - 2 as DWord))
|
|
expectEqual(127, Int8(truncatingIfNeeded: 127 as UDWord))
|
|
expectEqual(-127, Int8(truncatingIfNeeded: 129 as UDWord))
|
|
expectEqual(0b1111_1100, UInt8(truncatingIfNeeded: -4 as DWord))
|
|
expectEqual(0b1111_1100, UInt8(truncatingIfNeeded: -1 << 67 - 4 as DWord))
|
|
expectEqual(128, UInt8(truncatingIfNeeded: 128 + 1024 as UDWord))
|
|
expectEqual(129, UInt8(truncatingIfNeeded: 129 + 1024 as UDWord))
|
|
}
|
|
|
|
tests.test("Parsing/LosslessStringConvertible") {
|
|
func _toArray<T: LosslessStringConvertible>(_ text: String) -> [T] {
|
|
return text.split(separator: " ").map { T(String($0)) }.flatMap { $0 }
|
|
}
|
|
|
|
expectEqualSequence([1, 2, 3], _toArray("1 2 3") as [Int])
|
|
expectEqualSequence(
|
|
[Int](), _toArray("21-50 ff6600 10000000000000000000000000") as [Int])
|
|
}
|
|
|
|
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("words") {
|
|
expectEqualSequence([UInt.max], UInt.max.words)
|
|
expectEqualSequence([0xFF as UInt], UInt8.max.words)
|
|
expectEqualSequence([0xFFFF as UInt], UInt16.max.words)
|
|
expectEqualSequence([0xFFFFFFFF as UInt], UInt32.max.words)
|
|
|
|
expectEqualSequence([0 as UInt], UInt.min.words)
|
|
expectEqualSequence([0 as UInt], UInt8.min.words)
|
|
expectEqualSequence([0 as UInt], UInt16.min.words)
|
|
expectEqualSequence([0 as UInt], UInt32.min.words)
|
|
|
|
expectEqualSequence([UInt.max >> 1], Int.max.words)
|
|
expectEqualSequence([0x7F as UInt], Int8.max.words)
|
|
expectEqualSequence([0x7FFF as UInt], Int16.max.words)
|
|
expectEqualSequence([0x7FFFFFFF as UInt], Int32.max.words)
|
|
|
|
expectEqualSequence([UInt.max << (Int.bitWidth - 1)], Int.min.words)
|
|
expectEqualSequence([UInt.max << 7], Int8.min.words)
|
|
expectEqualSequence([UInt.max << 15], Int16.min.words)
|
|
expectEqualSequence([UInt.max << 31], Int32.min.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)
|
|
|
|
% if int(WORD_BITS) == 64:
|
|
expectEqualSequence([UInt.max], UInt64.max.words)
|
|
expectEqualSequence([0 as UInt], UInt64.min.words)
|
|
expectEqualSequence([UInt.max >> 1], Int64.max.words)
|
|
expectEqualSequence([(1 as UInt) << 63], Int64.min.words)
|
|
expectEqualSequence([UInt.max], (-1 as Int64).words)
|
|
% else:
|
|
expectEqualSequence([UInt.max, UInt.max], Int64.max.words)
|
|
expectEqualSequence([0 as UInt, 0], UInt64.min.words)
|
|
expectEqualSequence([UInt.max, UInt.max >> 1], Int64.max.words)
|
|
expectEqualSequence([0 as UInt, 1 << 31], Int64.min.words)
|
|
expectEqualSequence([UInt.max, UInt.max], (-1 as Int64).words)
|
|
% end
|
|
|
|
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<T : BinaryInteger>(_ 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")
|
|
|
|
typealias UInt128 = DoubleWidth<UInt64>
|
|
typealias UInt256 = DoubleWidth<UInt128>
|
|
typealias UInt512 = DoubleWidth<UInt256>
|
|
typealias UInt1024 = DoubleWidth<UInt512>
|
|
|
|
typealias Int128 = DoubleWidth<Int64>
|
|
typealias Int256 = DoubleWidth<Int128>
|
|
typealias Int512 = DoubleWidth<Int256>
|
|
typealias Int1024 = DoubleWidth<Int512>
|
|
|
|
dwTests.test("Literals") {
|
|
let w: DoubleWidth<UInt8> = 100
|
|
expectTrue(w == 100 as Int)
|
|
|
|
let x: DoubleWidth<UInt8> = 1000
|
|
expectTrue(x == 1000 as Int)
|
|
|
|
let y: DoubleWidth<Int8> = 1000
|
|
expectTrue(y == 1000 as Int)
|
|
|
|
let z: DoubleWidth<Int8> = -1000
|
|
expectTrue(z == -1000 as Int)
|
|
}
|
|
|
|
dwTests.test("Arithmetic/unsigned") {
|
|
let x: DoubleWidth<UInt8> = 1000
|
|
let y: DoubleWidth<UInt8> = 1111
|
|
expectEqual(x + 1, 1001)
|
|
expectEqual(x + x, 2000)
|
|
expectEqual(x - 1, 999)
|
|
expectEqual(x - x, 0)
|
|
expectEqual(y - x, 111)
|
|
|
|
expectEqual(x * 7, 7000)
|
|
expectEqual(y * 7, 7777)
|
|
|
|
expectEqual(x / 3, 333)
|
|
expectEqual(x / x, 1)
|
|
expectEqual(x / y, 0)
|
|
expectEqual(y / x, 1)
|
|
|
|
expectEqual(x % 3, 1)
|
|
expectEqual(x % y, x)
|
|
}
|
|
|
|
dwTests.test("Arithmetic/signed") {
|
|
let x: DoubleWidth<Int8> = 1000
|
|
let y: DoubleWidth<Int8> = -1111
|
|
expectEqual(x + 1, 1001)
|
|
expectEqual(x + x, 2000)
|
|
expectEqual(x - 1, 999)
|
|
expectEqual(x - x, 0)
|
|
expectEqual(0 - x, -1000)
|
|
expectEqual(x + y, -111)
|
|
expectEqual(x - y, 2111)
|
|
|
|
expectEqual(x * 7, 7000)
|
|
expectEqual(y * 7, -7777)
|
|
expectEqual(x * -7, -7000)
|
|
expectEqual(y * -7, 7777)
|
|
|
|
expectEqual(x / 3, 333)
|
|
expectEqual(x / -3, -333)
|
|
expectEqual(x / x, 1)
|
|
expectEqual(x / y, 0)
|
|
expectEqual(y / x, -1)
|
|
expectEqual(y / y, 1)
|
|
|
|
expectEqual(x % 3, 1)
|
|
expectEqual(x % -3, 1)
|
|
expectEqual(y % 3, -1)
|
|
expectEqual(y % -3, -1)
|
|
|
|
expectEqual(-y, 1111)
|
|
expectEqual(-x, -1000)
|
|
}
|
|
|
|
dwTests.test("Nested") {
|
|
do {
|
|
let x = UInt1024.max
|
|
let (y, o) = x.addingReportingOverflow(1)
|
|
expectEqual(y, 0)
|
|
expectTrue(y == (0 as Int))
|
|
expectTrue(o)
|
|
}
|
|
|
|
do {
|
|
let x = Int1024.max
|
|
let (y, o) = x.addingReportingOverflow(1)
|
|
expectEqual(y, Int1024.min)
|
|
expectLT(y, 0)
|
|
expectTrue(y < (0 as Int))
|
|
expectTrue(y < (0 as UInt))
|
|
expectTrue(o)
|
|
}
|
|
|
|
expectFalse(UInt1024.isSigned)
|
|
expectEqual(UInt1024.bitWidth, 1024)
|
|
expectTrue(Int1024.isSigned)
|
|
expectEqual(Int1024.bitWidth, 1024)
|
|
|
|
expectEqualSequence(UInt1024.max.words, repeatElement(UInt.max, count: 1024 / UInt.bitWidth))
|
|
}
|
|
|
|
dwTests.test("inits") {
|
|
typealias DWU16 = DoubleWidth<UInt8>
|
|
|
|
expectTrue(DWU16(UInt16.max) == UInt16.max)
|
|
expectNil(DWU16(exactly: UInt32.max))
|
|
expectEqual(DWU16(truncatingIfNeeded: UInt64.max), DWU16.max)
|
|
|
|
expectCrashLater()
|
|
_ = DWU16(UInt32.max)
|
|
}
|
|
|
|
dwTests.test("TwoWords") {
|
|
typealias DW = DoubleWidth<Int>
|
|
|
|
expectEqual(-1 as DW, DW(truncatingIfNeeded: -1 as Int8))
|
|
|
|
expectNil(Int(exactly: DW(Int.min) - 1))
|
|
expectNil(Int(exactly: DW(Int.max) + 1))
|
|
|
|
expectTrue(DW(Int.min) - 1 < Int.min)
|
|
expectTrue(DW(Int.max) + 1 > Int.max)
|
|
}
|
|
|
|
dwTests.test("Bitshifts") {
|
|
typealias DWU16 = DoubleWidth<UInt8>
|
|
typealias DWU32 = DoubleWidth<DWU16>
|
|
typealias DWU64 = DoubleWidth<DWU32>
|
|
|
|
func f(_ x: UInt64) {
|
|
let y = DWU64(x)
|
|
for i in -65...65 {
|
|
expectTrue(x << i == y << i)
|
|
expectTrue(x >> i == y >> i)
|
|
}
|
|
}
|
|
|
|
f(1)
|
|
f(~(~0 >> 1))
|
|
f(.max)
|
|
f(0b11110000_10100101_11110000_10100101_11110000_10100101_11110000_10100101)
|
|
}
|
|
|
|
dwTests.test("Remainder/DividingBy0") {
|
|
func f(_ x: Int1024, _ y: Int1024) -> Int1024 {
|
|
return x % y
|
|
}
|
|
expectCrashLater()
|
|
_ = f(42, 0)
|
|
}
|
|
|
|
dwTests.test("Division/By0") {
|
|
func f(_ x: Int1024, _ y: Int1024) -> Int1024 {
|
|
return x / y
|
|
}
|
|
expectCrashLater()
|
|
_ = f(42, 0)
|
|
}
|
|
|
|
dwTests.test("DivideMinByMinusOne") {
|
|
func f(_ x: Int1024) -> Int1024 {
|
|
return x / -1
|
|
}
|
|
expectCrashLater()
|
|
_ = f(Int1024.min)
|
|
}
|
|
|
|
dwTests.test("MultiplyMinByMinusOne") {
|
|
func f(_ x: Int1024) -> Int1024 {
|
|
return x * -1
|
|
}
|
|
expectCrashLater()
|
|
_ = f(Int1024.min)
|
|
}
|
|
|
|
typealias DWI16 = DoubleWidth<Int8>
|
|
typealias DWU16 = DoubleWidth<UInt8>
|
|
|
|
dwTests.test("Conversions") {
|
|
expectTrue(DWI16(1 << 15 - 1) == Int(1 << 15 - 1))
|
|
expectTrue(DWI16(-1 << 15) == Int(-1 << 15))
|
|
expectTrue(DWU16(1 << 16 - 1) == Int(1 << 16 - 1))
|
|
expectTrue(DWU16(0) == Int(0))
|
|
|
|
expectTrue(DWI16(Double(1 << 15 - 1)) == Int(1 << 15 - 1))
|
|
expectTrue(DWI16(Double(-1 << 15)) == Int(-1 << 15))
|
|
expectTrue(DWU16(Double(1 << 16 - 1)) == Int(1 << 16 - 1))
|
|
expectTrue(DWU16(Double(0)) == Int(0))
|
|
|
|
expectTrue(DWI16(Double(1 << 15 - 1) + 0.9) == Int(1 << 15 - 1))
|
|
expectTrue(DWI16(Double(-1 << 15) - 0.9) == Int(-1 << 15))
|
|
expectTrue(DWU16(Double(1 << 16 - 1) + 0.9) == Int(1 << 16 - 1))
|
|
expectTrue(DWU16(Double(0) - 0.9) == Int(0))
|
|
|
|
expectEqual(DWI16(0.00001), 0)
|
|
expectEqual(DWU16(0.00001), 0)
|
|
}
|
|
|
|
dwTests.test("Exact Conversions") {
|
|
expectEqual(DWI16(Double(1 << 15 - 1)), DWI16(exactly: Double(1 << 15 - 1))!)
|
|
expectEqual(DWI16(Double(-1 << 15)), DWI16(exactly: Double(-1 << 15))!)
|
|
expectEqual(DWU16(Double(1 << 16 - 1)), DWU16(exactly: Double(1 << 16 - 1))!)
|
|
expectEqual(DWU16(Double(0)), DWU16(exactly: Double(0))!)
|
|
|
|
expectNil(DWI16(exactly: Double(1 << 15 - 1) + 0.9))
|
|
expectNil(DWI16(exactly: Double(-1 << 15) - 0.9))
|
|
expectNil(DWU16(exactly: Double(1 << 16 - 1) + 0.9))
|
|
expectNil(DWU16(exactly: Double(0) - 0.9))
|
|
|
|
expectNil(DWI16(exactly: Double(1 << 15)))
|
|
expectNil(DWI16(exactly: Double(-1 << 15) - 1))
|
|
expectNil(DWU16(exactly: Double(1 << 16)))
|
|
expectNil(DWU16(exactly: Double(-1)))
|
|
|
|
expectNil(DWI16(exactly: 0.00001))
|
|
expectNil(DWU16(exactly: 0.00001))
|
|
|
|
expectNil(DWU16(exactly: Double.nan))
|
|
expectNil(DWU16(exactly: Float.nan))
|
|
expectNil(DWU16(exactly: Double.infinity))
|
|
expectNil(DWU16(exactly: Float.infinity))
|
|
}
|
|
|
|
dwTests.test("Conversions/SignedMax+1") {
|
|
expectCrashLater()
|
|
_ = DWI16(1 << 15)
|
|
}
|
|
|
|
dwTests.test("Conversions/SignedMin-1") {
|
|
expectCrashLater()
|
|
_ = DWI16(-1 << 15 - 1)
|
|
}
|
|
|
|
dwTests.test("Conversions/UnsignedMax+1") {
|
|
expectCrashLater()
|
|
_ = DWU16(1 << 16)
|
|
}
|
|
|
|
dwTests.test("Conversions/Unsigned-1") {
|
|
expectCrashLater()
|
|
_ = DWU16(-1)
|
|
}
|
|
|
|
dwTests.test("Words") {
|
|
expectEqualSequence((0 as DoubleWidth<Int8>).words, [0])
|
|
expectEqualSequence((1 as DoubleWidth<Int8>).words, [1])
|
|
expectEqualSequence((-1 as DoubleWidth<Int8>).words, [UInt.max])
|
|
expectEqualSequence((256 as DoubleWidth<Int8>).words, [256])
|
|
expectEqualSequence((-256 as DoubleWidth<Int8>).words, [UInt.max - 255])
|
|
expectEqualSequence(DoubleWidth<Int8>.max.words, [32767])
|
|
expectEqualSequence(DoubleWidth<Int8>.min.words, [UInt.max - 32767])
|
|
|
|
expectEqualSequence((0 as Int1024).words,
|
|
repeatElement(0 as UInt, count: 1024 / UInt.bitWidth))
|
|
expectEqualSequence((-1 as Int1024).words,
|
|
repeatElement(UInt.max, count: 1024 / UInt.bitWidth))
|
|
expectEqualSequence((1 as Int1024).words,
|
|
[1] + Array(repeating: 0, count: 1024 / UInt.bitWidth - 1))
|
|
}
|
|
|
|
runAllTests()
|