mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Returning `Self` was probably a hack from when shifts were required to be homogenous and we didn't have good generic inits between integer types. Returning Int is more natural, because: 1. Dimensional analysis says that we shouldn't expect the logarithm to have the same type. 2. Int is guaranteed to be able to represent any object size, and BinaryInteger does not admit sparse representations, so the logarithm of the value cannot exceed allocated storage size. 3. Every single use case in the stdlib and tests is either unchanged or simplified by this change.
908 lines
26 KiB
Swift
908 lines
26 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: %empty-directory(%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}
|
|
|
|
struct MockBinaryInteger<T : BinaryInteger> {
|
|
var _value: T
|
|
|
|
init(_ value: T) {
|
|
_value = value
|
|
}
|
|
}
|
|
|
|
extension MockBinaryInteger : CustomStringConvertible {
|
|
var description: String {
|
|
return _value.description
|
|
}
|
|
}
|
|
|
|
extension MockBinaryInteger : ExpressibleByIntegerLiteral {
|
|
init(integerLiteral value: T.IntegerLiteralType) {
|
|
_value = T(integerLiteral: value)
|
|
}
|
|
}
|
|
|
|
extension MockBinaryInteger : Comparable {
|
|
static func < (lhs: MockBinaryInteger<T>, rhs: MockBinaryInteger<T>) -> Bool {
|
|
return lhs._value < rhs._value
|
|
}
|
|
|
|
static func == (
|
|
lhs: MockBinaryInteger<T>, rhs: MockBinaryInteger<T>
|
|
) -> Bool {
|
|
return lhs._value == rhs._value
|
|
}
|
|
}
|
|
|
|
extension MockBinaryInteger : Hashable {
|
|
var hashValue: Int {
|
|
return _value.hashValue
|
|
}
|
|
}
|
|
|
|
extension MockBinaryInteger : BinaryInteger {
|
|
static var isSigned: Bool {
|
|
return T.isSigned
|
|
}
|
|
|
|
init<Source>(_ source: Source) where Source : BinaryFloatingPoint {
|
|
_value = T(source)
|
|
}
|
|
|
|
init?<Source>(exactly source: Source) where Source : BinaryFloatingPoint {
|
|
guard let result = T(exactly: source) else { return nil }
|
|
_value = result
|
|
}
|
|
|
|
init<Source>(_ source: Source) where Source : BinaryInteger {
|
|
_value = T(source)
|
|
}
|
|
|
|
init?<Source>(exactly source: Source) where Source : BinaryInteger {
|
|
guard let result = T(exactly: source) else { return nil }
|
|
_value = result
|
|
}
|
|
|
|
init<Source>(truncatingIfNeeded source: Source) where Source : BinaryInteger {
|
|
_value = T(truncatingIfNeeded: source)
|
|
}
|
|
|
|
init<Source>(clamping source: Source) where Source : BinaryInteger {
|
|
_value = T(clamping: source)
|
|
}
|
|
|
|
var magnitude: MockBinaryInteger<T.Magnitude> {
|
|
return MockBinaryInteger<T.Magnitude>(_value.magnitude)
|
|
}
|
|
|
|
var words: T.Words {
|
|
return _value.words
|
|
}
|
|
|
|
var bitWidth: Int {
|
|
return _value.bitWidth
|
|
}
|
|
|
|
var trailingZeroBitCount: Int {
|
|
return _value.trailingZeroBitCount
|
|
}
|
|
|
|
static func + (
|
|
lhs: MockBinaryInteger<T>, rhs: MockBinaryInteger<T>
|
|
) -> MockBinaryInteger<T> {
|
|
return MockBinaryInteger(lhs._value + rhs._value)
|
|
}
|
|
|
|
static func += (lhs: inout MockBinaryInteger<T>, rhs: MockBinaryInteger<T>) {
|
|
lhs._value += rhs._value
|
|
}
|
|
|
|
static func - (
|
|
lhs: MockBinaryInteger<T>, rhs: MockBinaryInteger<T>
|
|
) -> MockBinaryInteger<T> {
|
|
return MockBinaryInteger(lhs._value - rhs._value)
|
|
}
|
|
|
|
static func -= (lhs: inout MockBinaryInteger<T>, rhs: MockBinaryInteger<T>) {
|
|
lhs._value -= rhs._value
|
|
}
|
|
|
|
static func * (
|
|
lhs: MockBinaryInteger<T>, rhs: MockBinaryInteger<T>
|
|
) -> MockBinaryInteger<T> {
|
|
return MockBinaryInteger(lhs._value * rhs._value)
|
|
}
|
|
|
|
static func *= (lhs: inout MockBinaryInteger<T>, rhs: MockBinaryInteger<T>) {
|
|
lhs._value *= rhs._value
|
|
}
|
|
|
|
static func / (
|
|
lhs: MockBinaryInteger<T>, rhs: MockBinaryInteger<T>
|
|
) -> MockBinaryInteger<T> {
|
|
return MockBinaryInteger(lhs._value / rhs._value)
|
|
}
|
|
|
|
static func /= (lhs: inout MockBinaryInteger<T>, rhs: MockBinaryInteger<T>) {
|
|
lhs._value /= rhs._value
|
|
}
|
|
|
|
static func % (
|
|
lhs: MockBinaryInteger<T>, rhs: MockBinaryInteger<T>
|
|
) -> MockBinaryInteger<T> {
|
|
return MockBinaryInteger(lhs._value % rhs._value)
|
|
}
|
|
|
|
static func %= (lhs: inout MockBinaryInteger<T>, rhs: MockBinaryInteger<T>) {
|
|
lhs._value %= rhs._value
|
|
}
|
|
|
|
static func &= (lhs: inout MockBinaryInteger<T>, rhs: MockBinaryInteger<T>) {
|
|
lhs._value &= rhs._value
|
|
}
|
|
|
|
static func |= (lhs: inout MockBinaryInteger<T>, rhs: MockBinaryInteger<T>) {
|
|
lhs._value |= rhs._value
|
|
}
|
|
|
|
static func ^= (lhs: inout MockBinaryInteger<T>, rhs: MockBinaryInteger<T>) {
|
|
lhs._value ^= rhs._value
|
|
}
|
|
|
|
static prefix func ~ (x: MockBinaryInteger<T>) -> MockBinaryInteger<T> {
|
|
return MockBinaryInteger(~x._value)
|
|
}
|
|
|
|
static func >>= <RHS>(
|
|
lhs: inout MockBinaryInteger<T>, rhs: RHS
|
|
) where RHS : BinaryInteger {
|
|
lhs._value >>= rhs
|
|
}
|
|
|
|
static func <<= <RHS>(
|
|
lhs: inout MockBinaryInteger<T>, rhs: RHS
|
|
) where RHS : BinaryInteger {
|
|
lhs._value <<= rhs
|
|
}
|
|
}
|
|
|
|
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}/Add/MaskingOverflow") {
|
|
expectEqual(${Type}.min, ${Type}.max &+ 1)
|
|
}
|
|
|
|
tests.test("${Type}/Subtract/Underflow") {
|
|
func f(_ x: ${Type}) -> ${Type} {
|
|
return x - 1
|
|
}
|
|
expectCrashLater()
|
|
_ = f(${Type}.min)
|
|
}
|
|
|
|
tests.test("${Type}/Subtract/MaskingUnderflow") {
|
|
expectEqual(${Type}.max, ${Type}.min &- 1)
|
|
}
|
|
|
|
tests.test("${Type}/Multiply/MaskingOverflow") {
|
|
expectEqual(${Type}.min, (${Type}.max / 2 + 1) &* 2)
|
|
}
|
|
|
|
tests.test("${Type}/AddInPlace/Overflow") {
|
|
func f(_ x: inout ${Type}) {
|
|
x += 1
|
|
}
|
|
expectCrashLater()
|
|
var x = ${Type}.max
|
|
f(&x)
|
|
}
|
|
|
|
tests.test("${Type}/AddInPlace/MaskingOverflow") {
|
|
var x = ${Type}.max
|
|
x &+= 1
|
|
expectEqual(${Type}.min, x)
|
|
}
|
|
|
|
tests.test("${Type}/SubtractInPlace/Underflow") {
|
|
func f(_ x: inout ${Type}) {
|
|
x -= 1
|
|
}
|
|
expectCrashLater()
|
|
var x = ${Type}.min
|
|
f(&x)
|
|
}
|
|
|
|
tests.test("${Type}/SubtractInPlace/MaskingUnderflow") {
|
|
var x = ${Type}.min
|
|
x &-= 1
|
|
expectEqual(${Type}.max, x)
|
|
}
|
|
|
|
tests.test("${Type}/MultiplyInPlace/MaskingOverflow") {
|
|
var x = ${Type}.max / 2 + 1
|
|
x &*= 2
|
|
expectEqual(${Type}.min, 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], UInt64.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("RemainderReportingOverflow/DividingByMinusOne") {
|
|
// Work around SR-5964.
|
|
func minusOne<T : SignedInteger>() -> T {
|
|
return -1 as T
|
|
}
|
|
func f(_ x: Int, _ y: Int) -> Int {
|
|
return x.remainderReportingOverflow(dividingBy: y).partialValue
|
|
}
|
|
expectEqual(f(.max, minusOne()), 0)
|
|
expectEqual(f(.min, minusOne()), 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("Strideable") {
|
|
func dist<T: BinaryInteger>(_ a: T, _ b: T) -> Int {
|
|
return a.distance(to: b)
|
|
}
|
|
% for u in ['U', '']:
|
|
let ${u}x = ${u}Int.max - 10
|
|
expectEqual(${u}x.advanced(by: 10), ${u}Int.max)
|
|
expectEqual(${u}Int.max.advanced(by: -10), ${u}x)
|
|
expectEqual(dist(${u}x, ${u}Int.max), 10)
|
|
expectEqual(dist(${u}Int.max, ${u}x), -10)
|
|
|
|
// FIXME: The compiler spuriously flags these as overflowing:
|
|
// https://bugs.swift.org/browse/SR-5882
|
|
// expectEqual(${u}x.distance(to: ${u}Int.max), 10)
|
|
% end
|
|
|
|
expectEqual(dist(UInt8.min, UInt8.max), 255)
|
|
expectEqual(dist(UInt8.max, UInt8.min), -255)
|
|
expectEqual(dist(Int8.min, Int8.max), 255)
|
|
expectEqual(dist(Int8.max, Int8.min), -255)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
tests.test("binaryLogarithm/generic") {
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<Int8>)._binaryLogarithm(),
|
|
(42 as Int8)._binaryLogarithm())
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<UInt8>)._binaryLogarithm(),
|
|
(42 as UInt8)._binaryLogarithm())
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<Int16>)._binaryLogarithm(),
|
|
(42 as Int16)._binaryLogarithm())
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<UInt16>)._binaryLogarithm(),
|
|
(42 as UInt16)._binaryLogarithm())
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<Int32>)._binaryLogarithm(),
|
|
(42 as Int32)._binaryLogarithm())
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<UInt32>)._binaryLogarithm(),
|
|
(42 as UInt32)._binaryLogarithm())
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<Int64>)._binaryLogarithm(),
|
|
(42 as Int64)._binaryLogarithm())
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<UInt64>)._binaryLogarithm(),
|
|
(42 as UInt64)._binaryLogarithm())
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<Int>)._binaryLogarithm(),
|
|
(42 as Int)._binaryLogarithm())
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<UInt>)._binaryLogarithm(),
|
|
(42 as UInt)._binaryLogarithm())
|
|
// FIXME: DoubleWidth is no longer part of the standard library
|
|
#if false
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<DoubleWidth<Int>>)._binaryLogarithm(),
|
|
(42 as DoubleWidth<Int>)._binaryLogarithm())
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<DoubleWidth<UInt>>)._binaryLogarithm(),
|
|
(42 as DoubleWidth<UInt>)._binaryLogarithm())
|
|
expectEqual(
|
|
(42 as MockBinaryInteger<DoubleWidth<DoubleWidth<Int>>>)._binaryLogarithm(),
|
|
(42 as DoubleWidth<DoubleWidth<Int>>)._binaryLogarithm())
|
|
#endif
|
|
}
|
|
|
|
runAllTests()
|