From ea0474141f1a766e8e4f9d0cda9cf916073c5522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Bystr=C3=B6m=20Ericsson?= Date: Sat, 26 Oct 2024 08:06:23 +0200 Subject: [PATCH] [Tests] Rework of BinaryInteger+Shift.swift (#108) (#110). Lots and lots and lots and lots and lots and lots and lots of fuzzing. --- Sources/TestKit2/Utilities+Reduce.swift | 28 +- Tests/CoreKitTests/CoreInt+Shift.swift | 68 -- Tests/DoubleIntKitTests/DoubleInt+Shift.swift | 131 ---- Tests/InfiniIntKitTests/InfiniInt+Shift.swift | 248 ------- Tests/StdlibIntKitTests/StdlibInt+Shift.swift | 65 +- .../BinaryInteger+Shift.swift | 687 ++++++++++++------ 6 files changed, 521 insertions(+), 706 deletions(-) delete mode 100644 Tests/CoreKitTests/CoreInt+Shift.swift delete mode 100644 Tests/DoubleIntKitTests/DoubleInt+Shift.swift delete mode 100644 Tests/InfiniIntKitTests/InfiniInt+Shift.swift diff --git a/Sources/TestKit2/Utilities+Reduce.swift b/Sources/TestKit2/Utilities+Reduce.swift index 94ebb646..fe7102db 100644 --- a/Sources/TestKit2/Utilities+Reduce.swift +++ b/Sources/TestKit2/Utilities+Reduce.swift @@ -11,26 +11,26 @@ // MARK: * Utilities x Reduce //*============================================================================* -@inlinable public func reduce( - _ transform: (consuming T) throws -> T, - _ rhs: T -) rethrows -> T { +@inlinable public func reduce( + _ transform: (consuming A) throws -> B, + _ rhs: A +) rethrows -> B { try transform(rhs) } -@inlinable public func reduce( - _ lhs: consuming T, - _ transform: (consuming T, borrowing T) throws -> T, - _ rhs: borrowing T -) rethrows -> T { +@inlinable public func reduce( + _ lhs: consuming A, + _ transform: (consuming A, borrowing B) throws -> C, + _ rhs: borrowing B +) rethrows -> C { try transform(lhs, rhs) } -@inlinable public func reduce( - _ lhs: consuming T, - _ transform: (inout T, borrowing T) throws -> Void, - _ rhs: borrowing T -) rethrows -> T { +@inlinable public func reduce( + _ lhs: consuming A, + _ transform: (inout A, borrowing B) throws -> Void, + _ rhs: borrowing B +) rethrows -> A { try transform(&lhs, rhs) return lhs } diff --git a/Tests/CoreKitTests/CoreInt+Shift.swift b/Tests/CoreKitTests/CoreInt+Shift.swift deleted file mode 100644 index fea68264..00000000 --- a/Tests/CoreKitTests/CoreInt+Shift.swift +++ /dev/null @@ -1,68 +0,0 @@ -//=----------------------------------------------------------------------------= -// This source file is part of the Ultimathnum open source project. -// -// Copyright (c) 2023 Oscar Byström Ericsson -// Licensed under Apache License, Version 2.0 -// -// See http://www.apache.org/licenses/LICENSE-2.0 for license information. -//=----------------------------------------------------------------------------= - -import CoreKit -import TestKit - -//*============================================================================* -// MARK: * Core Int x Shift -//*============================================================================* - -extension CoreIntTests { - - //=------------------------------------------------------------------------= - // MARK: Tests - //=------------------------------------------------------------------------= - - func testUpshift() { - func whereIs(_ type: T.Type) where T: SystemsInteger { - Test().upshift( 1 as T, 0 as T, 1 as T) - Test().upshift( 1 as T, 1 as T, 2 as T) - Test().upshift( 1 as T, 2 as T, 4 as T) - Test().upshift( 1 as T, 3 as T, 8 as T) - - Test().upshift( 1 as T, T .min, T( Bit(!T.isSigned))) - Test().upshift(~0 as T, T .min, T(repeating: Bit.one )) - Test().upshift( 1 as T, T .max, T(repeating: Bit.zero)) - Test().upshift(~0 as T, T .max, T(repeating: Bit.zero)) - - Test().upshift( 1 as T, ~T .msb, T(repeating: Bit.zero)) - Test().upshift(~0 as T, ~T .msb, T(repeating: Bit.zero)) - Test().upshift( 1 as T, T .msb, T(repeating: Bit.zero)) - Test().upshift(~0 as T, T .msb, T(repeating: Bit( T.isSigned))) - } - - for type in Self.types { - whereIs(type) - } - } - - func testDownshift() { - func whereIs(_ type: T.Type) where T: SystemsInteger { - Test().downshift( 8 as T, 0 as T, 8 as T) - Test().downshift( 8 as T, 1 as T, 4 as T) - Test().downshift( 8 as T, 2 as T, 2 as T) - Test().downshift( 8 as T, 3 as T, 1 as T) - - Test().downshift( 1 as T, T .min, T( Bit(!T.isSigned))) - Test().downshift(~0 as T, T .min, T(repeating: Bit(!T.isSigned))) - Test().downshift( 1 as T, T .max, T(repeating: Bit.zero)) - Test().downshift(~0 as T, T .max, T(repeating: Bit( T.isSigned))) - - Test().downshift( 1 as T, ~T .msb, T(repeating: Bit.zero)) - Test().downshift(~0 as T, ~T .msb, T(repeating: Bit( T.isSigned))) - Test().downshift( 1 as T, T .msb, T(repeating: Bit.zero)) - Test().downshift(~0 as T, T .msb, T(repeating: Bit.zero)) - } - - for type in Self.types { - whereIs(type) - } - } -} diff --git a/Tests/DoubleIntKitTests/DoubleInt+Shift.swift b/Tests/DoubleIntKitTests/DoubleInt+Shift.swift deleted file mode 100644 index 2ccdf65b..00000000 --- a/Tests/DoubleIntKitTests/DoubleInt+Shift.swift +++ /dev/null @@ -1,131 +0,0 @@ -//=----------------------------------------------------------------------------= -// This source file is part of the Ultimathnum open source project. -// -// Copyright (c) 2023 Oscar Byström Ericsson -// Licensed under Apache License, Version 2.0 -// -// See http://www.apache.org/licenses/LICENSE-2.0 for license information. -//=----------------------------------------------------------------------------= - -import CoreKit -import DoubleIntKit -import TestKit - -//*============================================================================* -// MARK: * Double Int x Shift -//*============================================================================* - -extension DoubleIntTests { - - //=------------------------------------------------------------------------= - // MARK: Tests - //=------------------------------------------------------------------------= - - func testUpshift() { - func whereTheBaseTypeIs(_ type: B.Type) where B: SystemsInteger { - typealias T = DoubleInt - //=----------------------------------= - let low = T.zero - let mid = T(IX(size: B.self)) - let top = T(IX(size: T.self)) - //=----------------------------------= - Test().upshift(T(low: 1, high: 2), low + 0 as T, T(low: 1, high: 2)) - Test().upshift(T(low: 1, high: 2), low + 1 as T, T(low: 2, high: 4)) - Test().upshift(T(low: 1, high: 2), low + 2 as T, T(low: 4, high: 8)) - Test().upshift(T(low: 1, high: 2), low + 3 as T, T(low: 8, high: 16)) - - Test().upshift(T(low: 1, high: 2), mid - 3 as T, T(low: B.Magnitude.msb / 4, high: B(raw: B.Magnitude.msb / 2))) - Test().upshift(T(low: 1, high: 2), mid - 2 as T, T(low: B.Magnitude.msb / 2, high: B(raw: B.Magnitude.msb ))) - Test().upshift(T(low: 1, high: 2), mid - 1 as T, T(low: B.Magnitude.msb, high: 000000000000000000000000000)) - Test().upshift(T(low: 1, high: 2), mid + 0 as T, T(low: 0, high: 1)) - Test().upshift(T(low: 1, high: 2), mid + 1 as T, T(low: 0, high: 2)) - Test().upshift(T(low: 1, high: 2), mid + 2 as T, T(low: 0, high: 4)) - Test().upshift(T(low: 1, high: 2), mid + 3 as T, T(low: 0, high: 8)) - - Test().upshift(T(low: 1, high: 2), top - 0 as T, T(low: 0, high: 0)) - Test().upshift(T(low: 1, high: 2), top - 1 as T, T(low: 0, high: B(raw: B.Magnitude.msb ))) - Test().upshift(T(low: 1, high: 2), top - 2 as T, T(low: 0, high: B(raw: B.Magnitude.msb / 2))) - Test().upshift(T(low: 1, high: 2), top - 3 as T, T(low: 0, high: B(raw: B.Magnitude.msb / 4))) - } - - for base in Self.bases { - whereTheBaseTypeIs(base) - } - } - - func testDownshift() { - func whereTheBaseTypeIs(_ type: B.Type) where B: SystemsInteger { - typealias T = DoubleInt - //=----------------------------------= - let low = T.zero - let mid = T(IX(size: B.self)) - let top = T(IX(size: T.self)) - //=----------------------------------= - Test().downshift(T(low: 8, high: 16), low + 0 as T, T(low: 8, high: 16)) - Test().downshift(T(low: 8, high: 16), low + 1 as T, T(low: 4, high: 8)) - Test().downshift(T(low: 8, high: 16), low + 2 as T, T(low: 2, high: 4)) - Test().downshift(T(low: 8, high: 16), low + 3 as T, T(low: 1, high: 2)) - - Test().downshift(T(low: 8, high: 16), mid + 0 as T, T(low: 16, high: 0)) - Test().downshift(T(low: 8, high: 16), mid + 1 as T, T(low: 8, high: 0)) - Test().downshift(T(low: 8, high: 16), mid + 2 as T, T(low: 4, high: 0)) - Test().downshift(T(low: 8, high: 16), mid + 3 as T, T(low: 2, high: 0)) - - if T.isSigned { - let x = B.Magnitude.msb - Test().downshift(T(low: 0, high: B.msb), mid - 3 as T, T(low: 0, high: ~3)) - Test().downshift(T(low: 0, high: B.msb), mid - 2 as T, T(low: 0, high: ~1)) - Test().downshift(T(low: 0, high: B.msb), mid - 1 as T, T(low: 0, high: ~0)) - Test().downshift(T(low: 0, high: B.msb), mid - 0 as T, T(low: x, high: ~0)) - - Test().downshift(T(low: 0, high: B.msb), top - 3 as T, T(low: ~3, high: ~0)) - Test().downshift(T(low: 0, high: B.msb), top - 2 as T, T(low: ~1, high: ~0)) - Test().downshift(T(low: 0, high: B.msb), top - 1 as T, T(low: ~0, high: ~0)) - Test().downshift(T(low: 0, high: B.msb), top - 0 as T, T(low: ~0, high: ~0)) - } else { - let x = B.Magnitude.msb - Test().downshift(T(low: 0, high: B.msb), mid - 3 as T, T(low: 0, high: 4)) - Test().downshift(T(low: 0, high: B.msb), mid - 2 as T, T(low: 0, high: 2)) - Test().downshift(T(low: 0, high: B.msb), mid - 1 as T, T(low: 0, high: 1)) - Test().downshift(T(low: 0, high: B.msb), mid - 0 as T, T(low: x, high: 0)) - - Test().downshift(T(low: 0, high: B.msb), top - 3 as T, T(low: 4, high: 0)) - Test().downshift(T(low: 0, high: B.msb), top - 2 as T, T(low: 2, high: 0)) - Test().downshift(T(low: 0, high: B.msb), top - 1 as T, T(low: 1, high: 0)) - Test().downshift(T(low: 0, high: B.msb), top - 0 as T, T(low: 0, high: 0)) - } - } - - for base in Self.bases { - whereTheBaseTypeIs(base) - } - } - - func testUpshiftByMinSigned() { - func whereIsSigned(_ type: T.Type) where T: SystemsInteger & SignedInteger { - for value in [T.zero, ~T.zero, T.min, ~T.min, T.max, ~T.max] { - Test().upshift(value, T.min, T(repeating: value.appendix)) - Test().upshift(value, T.min + 1, T(repeating: value.appendix)) - Test().upshift(value, T.min + 2, T(repeating: value.appendix)) - } - } - - for type in Self.typesWhereIsSigned { - whereIsSigned(type) - } - } - - func testDownshiftByMinSigned() { - func whereIsSigned(_ type: T.Type) where T: SystemsInteger & SignedInteger { - for value in [T.zero, ~T.zero, T.min, ~T.min, T.max, ~T.max] { - Test().downshift(value, T.min, T(repeating: Bit.zero)) - Test().downshift(value, T.min + 1, T(repeating: Bit.zero)) - Test().downshift(value, T.min + 2, T(repeating: Bit.zero)) - } - } - - for type in Self.typesWhereIsSigned { - whereIsSigned(type) - } - } -} diff --git a/Tests/InfiniIntKitTests/InfiniInt+Shift.swift b/Tests/InfiniIntKitTests/InfiniInt+Shift.swift deleted file mode 100644 index 3b7f6802..00000000 --- a/Tests/InfiniIntKitTests/InfiniInt+Shift.swift +++ /dev/null @@ -1,248 +0,0 @@ -//=----------------------------------------------------------------------------= -// This source file is part of the Ultimathnum open source project. -// -// Copyright (c) 2023 Oscar Byström Ericsson -// Licensed under Apache License, Version 2.0 -// -// See http://www.apache.org/licenses/LICENSE-2.0 for license information. -//=----------------------------------------------------------------------------= - -import CoreKit -import InfiniIntKit -import TestKit - -//*============================================================================* -// MARK: * Infini Int x Shift -//*============================================================================* - -extension InfiniIntTests { - - //=------------------------------------------------------------------------= - // MARK: Tests - //=------------------------------------------------------------------------= - - func testUpshift() { - func whereIs(_ type: T.Type) where T: ArbitraryInteger { - //=----------------------------------= - let large: T = 0xFFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0 - //=----------------------------------= - for value: T in [large, ~large] { - let appendix = T(repeating: value.appendix) - - Test().upshift(value, 000 as T, T(0x0000FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0) ^ appendix & ~T(0x0000)) - Test().upshift(value, 001 as T, T(0x0001FFFDFBF9F7F5F3F1EFEDEBE9E7E5E3E0) ^ appendix & ~T(0x0001)) - Test().upshift(value, 002 as T, T(0x0003FFFBF7F3EFEBE7E3DFDBD7D3CFCBC7C0) ^ appendix & ~T(0x0003)) - Test().upshift(value, 003 as T, T(0x0007FFF7EFE7DFD7CFC7BFB7AFA79F978F80) ^ appendix & ~T(0x0007)) - Test().upshift(value, 004 as T, T(0x000FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F00) ^ appendix & ~T(0x000F)) - Test().upshift(value, 005 as T, T(0x001FFFDFBF9F7F5F3F1EFEDEBE9E7E5E3E00) ^ appendix & ~T(0x001F)) - Test().upshift(value, 006 as T, T(0x003FFFBF7F3EFEBE7E3DFDBD7D3CFCBC7C00) ^ appendix & ~T(0x003F)) - Test().upshift(value, 007 as T, T(0x007FFF7EFE7DFD7CFC7BFB7AFA79F978F800) ^ appendix & ~T(0x007F)) - Test().upshift(value, 008 as T, T(0x00FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F000) ^ appendix & ~T(0x00FF)) - Test().upshift(value, 009 as T, T(0x01FFFDFBF9F7F5F3F1EFEDEBE9E7E5E3E000) ^ appendix & ~T(0x01FF)) - Test().upshift(value, 010 as T, T(0x03FFFBF7F3EFEBE7E3DFDBD7D3CFCBC7C000) ^ appendix & ~T(0x03FF)) - Test().upshift(value, 011 as T, T(0x07FFF7EFE7DFD7CFC7BFB7AFA79F978F8000) ^ appendix & ~T(0x07FF)) - Test().upshift(value, 012 as T, T(0x0FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0000) ^ appendix & ~T(0x0FFF)) - Test().upshift(value, 013 as T, T(0x1FFFDFBF9F7F5F3F1EFEDEBE9E7E5E3E0000) ^ appendix & ~T(0x1FFF)) - Test().upshift(value, 014 as T, T(0x3FFFBF7F3EFEBE7E3DFDBD7D3CFCBC7C0000) ^ appendix & ~T(0x3FFF)) - Test().upshift(value, 015 as T, T(0x7FFF7EFE7DFD7CFC7BFB7AFA79F978F80000) ^ appendix & ~T(0x7FFF)) - Test().upshift(value, 016 as T, T(0xFFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F00000) ^ appendix & ~T(0xFFFF)) - - infinite: if !T.isSigned { - for distance: T in (0...9).lazy.map(~) { - Test().upshift(value, distance, T.zero) - } - } - } - } - - for type in Self.types { - whereIs(type) - } - } - - func testDownshiftByMoreThanMaxSignedWordIsUpflush() { - func whereIs(_ type: T.Type) where T: ArbitraryInteger { - //=----------------------------------= - let large: T = 0xFFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0 - //=----------------------------------= - for value: T in [~2, ~1, ~0, 0, 1, 2, large, ~large] { - Test().upshift(value, large, T.zero) - Test().upshift(value, T(IX.max) + 1, T.zero) - Test().upshift(value, T(IX.max) + 2, T.zero) - Test().upshift(value, T(IX.max) + 3, T.zero) - Test().upshift(value, T(IX.max) + 4, T.zero) - - if T.isSigned { - Test().downshift(value, T(IX.min), T.zero) - Test().downshift(value, T(IX.min) - 1, T.zero) - Test().downshift(value, T(IX.min) - 2, T.zero) - Test().downshift(value, T(IX.min) - 3, T.zero) - } else { - Test().upshift(value, large.toggled(), T.zero) - Test().upshift(value, large.complement(), T.zero) - } - } - } - - for type in Self.types { - whereIs(type) - } - } - - func testDownshift() { - func whereIs(_ type: T.Type) where T: ArbitraryInteger { - //=----------------------------------= - let large: T = 0xFFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0 - //=----------------------------------= - for value: T in [large, ~large] { - let appendix = T(repeating: value.appendix) - - Test().downshift(value, 00000 as T, T(0xFFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0) ^ appendix) - Test().downshift(value, 00001 as T, T(0x7FFF7EFE7DFD7CFC7BFB7AFA79F978F8) ^ appendix) - Test().downshift(value, 00002 as T, T(0x3FFFBF7F3EFEBE7E3DFDBD7D3CFCBC7C) ^ appendix) - Test().downshift(value, 00003 as T, T(0x1FFFDFBF9F7F5F3F1EFEDEBE9E7E5E3E) ^ appendix) - Test().downshift(value, 00004 as T, T(0x0FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F) ^ appendix) - Test().downshift(value, 00005 as T, T(0x07FFF7EFE7DFD7CFC7BFB7AFA79F978F) ^ appendix) - Test().downshift(value, 00006 as T, T(0x03FFFBF7F3EFEBE7E3DFDBD7D3CFCBC7) ^ appendix) - Test().downshift(value, 00007 as T, T(0x01FFFDFBF9F7F5F3F1EFEDEBE9E7E5E3) ^ appendix) - Test().downshift(value, 00008 as T, T(0x00FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1) ^ appendix) - Test().downshift(value, 00009 as T, T(0x007FFF7EFE7DFD7CFC7BFB7AFA79F978) ^ appendix) - Test().downshift(value, 00010 as T, T(0x003FFFBF7F3EFEBE7E3DFDBD7D3CFCBC) ^ appendix) - Test().downshift(value, 00011 as T, T(0x001FFFDFBF9F7F5F3F1EFEDEBE9E7E5E) ^ appendix) - Test().downshift(value, 00012 as T, T(0x000FFFEFDFCFBFAF9F8F7F6F5F4F3F2F) ^ appendix) - Test().downshift(value, 00013 as T, T(0x0007FFF7EFE7DFD7CFC7BFB7AFA79F97) ^ appendix) - Test().downshift(value, 00014 as T, T(0x0003FFFBF7F3EFEBE7E3DFDBD7D3CFCB) ^ appendix) - Test().downshift(value, 00015 as T, T(0x0001FFFDFBF9F7F5F3F1EFEDEBE9E7E5) ^ appendix) - Test().downshift(value, 00016 as T, T(0x0000FFFEFDFCFBFAF9F8F7F6F5F4F3F2) ^ appendix) - - Test().downshift(value, 00126 as T, T(0x00000000000000000000000000000003) ^ appendix) - Test().downshift(value, 00127 as T, T(0x00000000000000000000000000000001) ^ appendix) - Test().downshift(value, 00128 as T, T(0x00000000000000000000000000000000) ^ appendix) - Test().downshift(value, 00129 as T, T(0x00000000000000000000000000000000) ^ appendix) - - Test().downshift(value, 99999 as T, T(0x00000000000000000000000000000000) ^ appendix) - Test().downshift(value, large as T, T(0x00000000000000000000000000000000) ^ appendix) - - infinite: if !T.isSigned { - for distance: T in (0...9).lazy.map(~) { - Test().downshift(value, distance, appendix) - } - } - } - } - - for types in Self.types { - whereIs(types) - } - } - - func testDownshiftByMoreThanMaxSignedWordIsDownflush() { - func whereIs(_ type: T.Type) where T: ArbitraryInteger { - //=----------------------------------= - let large: T = 0xFFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0 - //=----------------------------------= - for value: T in [~2, ~1, ~0, 0, 1, 2, large, ~large] { - let appendix = T(repeating: value.appendix) - - Test().downshift(value, large, appendix) - Test().downshift(value, T(IX.max) + 1, appendix) - Test().downshift(value, T(IX.max) + 2, appendix) - Test().downshift(value, T(IX.max) + 3, appendix) - Test().downshift(value, T(IX.max) + 4, appendix) - - if T.isSigned { - Test().upshift(value, T(IX.min), appendix) - Test().upshift(value, T(IX.min) - 1, appendix) - Test().upshift(value, T(IX.min) - 2, appendix) - Test().upshift(value, T(IX.min) - 3, appendix) - } else { - Test().downshift(value, large.toggled(), appendix) - Test().downshift(value, large.complement(), appendix) - } - } - } - - for type in Self.types { - whereIs(type) - } - } -} - -//=----------------------------------------------------------------------------= -// MARK: + Edge Cases -//=----------------------------------------------------------------------------= - -extension InfiniIntTests { - - //=------------------------------------------------------------------------= - // MARK: Tests - //=------------------------------------------------------------------------= - - func testUpshiftAtEdgeOfElement() { - func whereIs(_ type: T.Type) where T: ArbitraryInteger { - compact: do { - Test().upshift( T(IX.max >> 5), 4 as T, T(IX.max >> 5) * 16) - Test().upshift( T(IX.max >> 5), 5 as T, T(IX.max >> 5) * 32) - Test().upshift( T(IX.max >> 5), 6 as T, T(IX.max >> 5) * 64) - - Test().upshift(~T(IX.max >> 5), 4 as T, ~T(IX.max >> 5) &* 16) - Test().upshift(~T(IX.max >> 5), 5 as T, ~T(IX.max >> 5) &* 32) - Test().upshift(~T(IX.max >> 5), 6 as T, ~T(IX.max >> 5) &* 64) - } - - extended: do { - Test().upshift( T(UX.max >> 5), 4 as T, T(UX.max >> 5) * 16) - Test().upshift( T(UX.max >> 5), 5 as T, T(UX.max >> 5) * 32) - Test().upshift( T(UX.max >> 5), 6 as T, T(UX.max >> 5) * 64) - - Test().upshift(~T(UX.max >> 5), 4 as T, ~T(UX.max >> 5) &* 16) - Test().upshift(~T(UX.max >> 5), 5 as T, ~T(UX.max >> 5) &* 32) - Test().upshift(~T(UX.max >> 5), 6 as T, ~T(UX.max >> 5) &* 64) - } - } - - for type in Self.types { - whereIs(type) - } - } - - func testDownshiftByNonappendix() { - func whereIs(_ type: T.Type) where T: ArbitraryInteger { - Test().downshift( T(I8 .max), 6 as T, 1 as T) - Test().downshift( T(I8 .max), 7 as T, 0 as T) - Test().downshift( T(I8 .max), 8 as T, 0 as T) - - Test().downshift(~T(I8 .max), 6 as T, ~1 as T) - Test().downshift(~T(I8 .max), 7 as T, ~0 as T) - Test().downshift(~T(I8 .max), 8 as T, ~0 as T) - - Test().downshift( T(U8 .msb), 7 as T, 1 as T) - Test().downshift( T(U8 .msb), 8 as T, 0 as T) - Test().downshift( T(U8 .msb), 9 as T, 0 as T) - - Test().downshift(~T(U8 .msb), 7 as T, ~1 as T) - Test().downshift(~T(U8 .msb), 8 as T, ~0 as T) - Test().downshift(~T(U8 .msb), 9 as T, ~0 as T) - - Test().downshift( T(I64.max), 62 as T, 1 as T) - Test().downshift( T(I64.max), 63 as T, 0 as T) - Test().downshift( T(I64.max), 64 as T, 0 as T) - - Test().downshift(~T(I64.max), 62 as T, ~1 as T) - Test().downshift(~T(I64.max), 63 as T, ~0 as T) - Test().downshift(~T(I64.max), 64 as T, ~0 as T) - - Test().downshift( T(U64.msb), 63 as T, 1 as T) - Test().downshift( T(U64.msb), 64 as T, 0 as T) - Test().downshift( T(U64.msb), 65 as T, 0 as T) - - Test().downshift(~T(U64.msb), 63 as T, ~1 as T) - Test().downshift(~T(U64.msb), 64 as T, ~0 as T) - Test().downshift(~T(U64.msb), 65 as T, ~0 as T) - } - - for type in Self.types { - whereIs(type) - } - } -} diff --git a/Tests/StdlibIntKitTests/StdlibInt+Shift.swift b/Tests/StdlibIntKitTests/StdlibInt+Shift.swift index 81802bd5..78094b22 100644 --- a/Tests/StdlibIntKitTests/StdlibInt+Shift.swift +++ b/Tests/StdlibIntKitTests/StdlibInt+Shift.swift @@ -33,65 +33,64 @@ import TestKit2 // MARK: Tests //=------------------------------------------------------------------------= - @Test("StdlibInt.<<(_:_:) - [forwarding][entropic]", arguments: fuzzers) - func shift(_ randomness: consuming FuzzerInt) { - for _ in 0 ..< 32 { - let instance = IXL.entropic(size: 000256, using: &randomness) + @Test("StdlibInt.<<(_:_:)", .tags(.forwarding, .random), arguments: fuzzers) + func shift(_ randomness: consuming FuzzerInt) throws { + for _ in 0 ..< 128 { + let random = IXL.entropic(size: 000256, using: &randomness) let distance = IXL.random(in: -128...127, using: &randomness) - let expectation = instance << distance - Ɣexpect(StdlibInt(instance), up: StdlibInt(distance), is: StdlibInt(expectation)) + let expectation: IXL = random << distance + try Ɣrequire(StdlibInt(random), up: StdlibInt(distance), is: StdlibInt(expectation)) } } - @Test("StdlibInt.<<(_:_:) - Int.max [forwarding]") - func shiftByDistancesNearMaxInt() { - Ɣexpect(StdlibInt.zero, up: StdlibInt(Int.max) + 2, is: StdlibInt.zero) - Ɣexpect(StdlibInt.zero, up: StdlibInt(Int.max) + 1, is: StdlibInt.zero) - Ɣexpect(StdlibInt.zero, up: StdlibInt(Int.max), is: StdlibInt.zero) - Ɣexpect(StdlibInt.zero, up: StdlibInt(Int.max) - 1, is: StdlibInt.zero) - Ɣexpect(StdlibInt.zero, up: StdlibInt(Int.max) - 2, is: StdlibInt.zero) + @Test("StdlibInt.<<(_:_:) - Int.max", .tags(.forwarding)) + func shiftByDistancesNearMaxInt() throws { + try Ɣrequire(StdlibInt.zero, up: StdlibInt(Int.max) + 2, is: StdlibInt.zero) + try Ɣrequire(StdlibInt.zero, up: StdlibInt(Int.max) + 1, is: StdlibInt.zero) + try Ɣrequire(StdlibInt.zero, up: StdlibInt(Int.max), is: StdlibInt.zero) + try Ɣrequire(StdlibInt.zero, up: StdlibInt(Int.max) - 1, is: StdlibInt.zero) + try Ɣrequire(StdlibInt.zero, up: StdlibInt(Int.max) - 2, is: StdlibInt.zero) } - @Test("StdlibInt.<<(_:_:) - Int.min [forwarding][entropic]", arguments: fuzzers) - func shiftByDistancesNearMinInt(_ randomness: consuming FuzzerInt) { + @Test("StdlibInt.<<(_:_:) - Int.min", .tags(.forwarding, .random), arguments: fuzzers) + func shiftByDistancesNearMinInt(_ randomness: consuming FuzzerInt) throws { for _ in 0 ..< 32 { let random = StdlibInt(IXL.entropic(size: 256, using: &randomness)) let expectation = StdlibInt(IXL(repeating: Bit(random < 0))) - Ɣexpect(random, up: StdlibInt(Int.min) + 2, is: expectation) - Ɣexpect(random, up: StdlibInt(Int.min) + 1, is: expectation) - Ɣexpect(random, up: StdlibInt(Int.min), is: expectation) - Ɣexpect(random, up: StdlibInt(Int.min) - 1, is: expectation) - Ɣexpect(random, up: StdlibInt(Int.min) - 2, is: expectation) + try Ɣrequire(random, up: StdlibInt(Int.min) + 2, is: expectation) + try Ɣrequire(random, up: StdlibInt(Int.min) + 1, is: expectation) + try Ɣrequire(random, up: StdlibInt(Int.min), is: expectation) + try Ɣrequire(random, up: StdlibInt(Int.min) - 1, is: expectation) + try Ɣrequire(random, up: StdlibInt(Int.min) - 2, is: expectation) } } - /// - Note: This method checks `ascending` and `descending` shifts. - func Ɣexpect(_ instance: StdlibInt, up distance: StdlibInt, is expectation: StdlibInt, at location: SourceLocation = #_sourceLocation) { + func Ɣrequire(_ instance: StdlibInt, up distance: StdlibInt, is expectation: StdlibInt, at location: SourceLocation = #_sourceLocation) throws { //=--------------------------------------= let opposite: StdlibInt = -distance //=--------------------------------------= if instance != 0, distance >= 0 { - #expect((instance.bitWidth + Int(distance)) == expectation.bitWidth, sourceLocation: location) + try #require((instance.bitWidth + Int(distance)) == expectation.bitWidth, sourceLocation: location) } always: do { - #expect((instance << distance) == expectation, sourceLocation: location) - #expect({ var x = instance; x <<= distance; return x }() == expectation, sourceLocation: location) + try #require(reduce(instance, <<, distance) == expectation, sourceLocation: location) + try #require(reduce(instance, <<=, distance) == expectation, sourceLocation: location) } always: do { - #expect((instance >> opposite) == expectation, sourceLocation: location) - #expect({ var x = instance; x >>= opposite; return x }() == expectation, sourceLocation: location) + try #require(reduce(instance, >>, opposite) == expectation, sourceLocation: location) + try #require(reduce(instance, >>=, opposite) == expectation, sourceLocation: location) } - if let distance = Swift.Int(exactly: distance) { - #expect((instance << distance) == expectation, sourceLocation: location) - #expect({ var x = instance; x <<= distance; return x }() == expectation, sourceLocation: location) + if let distance = Swift.Int(exactly: distance) { + try #require(reduce(instance, <<, distance) == expectation, sourceLocation: location) + try #require(reduce(instance, <<=, distance) == expectation, sourceLocation: location) } - if let opposite = Swift.Int(exactly: opposite) { - #expect((instance >> opposite) == expectation, sourceLocation: location) - #expect({ var x = instance; x >>= opposite; return x }() == expectation, sourceLocation: location) + if let opposite = Swift.Int(exactly: opposite) { + try #require(reduce(instance, >>, opposite) == expectation, sourceLocation: location) + try #require(reduce(instance, >>=, opposite) == expectation, sourceLocation: location) } } } diff --git a/Tests/UltimathnumTests/BinaryInteger+Shift.swift b/Tests/UltimathnumTests/BinaryInteger+Shift.swift index dbee4275..b357553b 100644 --- a/Tests/UltimathnumTests/BinaryInteger+Shift.swift +++ b/Tests/UltimathnumTests/BinaryInteger+Shift.swift @@ -8,297 +8,560 @@ //=----------------------------------------------------------------------------= import CoreKit -import DoubleIntKit import InfiniIntKit -import TestKit +import RandomIntKit +import TestKit2 //*============================================================================* // MARK: * Binary Integer x Shift //*============================================================================* -final class BinaryIntegerTestsOnShifts: XCTestCase { +@Suite struct BinaryIntegerTestsOnShift { //=------------------------------------------------------------------------= - // MARK: Tests x Repeating Bit + // MARK: Tests //=------------------------------------------------------------------------= - func testUpshiftRepeatingBitByGenericDistancesAsArbitrayInteger() { - func whereIs(value: A.Type, distance: B.Type) where A: ArbitraryInteger, B: BinaryInteger { - //=----------------------------------= - let a0 = A(repeating: Bit.zero) - let a1 = A(repeating: Bit.one ) - //=----------------------------------= - for distance: B in (-4 as IX ..< 4).lazy.map(B.init(load:)) { - Test().upshift(a0, distance, a0) - } - - always: do { - Test().upshift(a1, 0 as B, a1 &* 1) - Test().upshift(a1, 1 as B, a1 &* 2) - Test().upshift(a1, 2 as B, a1 &* 4) - Test().upshift(a1, 3 as B, a1 &* 8) - } - - if B.isSigned { - Test().upshift(a1, ~0 as B, Bool(a1.appendix) ? a1 : a1 / 2) - Test().upshift(a1, ~1 as B, Bool(a1.appendix) ? a1 : a1 / 4) - Test().upshift(a1, ~2 as B, Bool(a1.appendix) ? a1 : a1 / 8) - Test().upshift(a1, ~3 as B, Bool(a1.appendix) ? a1 : a1 / 16) - } + @Test( + "BinaryInteger/shift: down(Shift)", + Tag.List.tags(.generic, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func down(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + try whereIs(type) + + func whereIs(_ type: T.Type) throws where T: BinaryInteger { + let size = IX(size: T.self) ?? 256 - if !B.isSigned, A.size <= Swift.max(B.size, Count(255 - 3)) { - Test().upshift(a1, ~0 as B, a0) // distance >= U8.max - 0 - Test().upshift(a1, ~1 as B, a0) // distance >= U8.max - 1 - Test().upshift(a1, ~2 as B, a0) // distance >= U8.max - 2 - Test().upshift(a1, ~3 as B, a0) // distance >= U8.max - 3 + for _ in 0 ..< conditional(debug: 32, release: 1024) { + let s = IX.random(in: 0..(Count(s))) + + try withOnlyOneCallToRequire((a, s, b)) { require in + a.withUnsafeBinaryIntegerElements(as: U8.self) { a in + b.withUnsafeBinaryIntegerElements(as: U8.self) { b in + for (i, j) in zip(s...s+size, 0...size) { + let x = a[UX(i / 8)][Shift(Count(i % 8))] + let y = b[UX(j / 8)][Shift(Count(j % 8))] + require(x == y) + } + } + } + } } + } + } + + @Test( + "BinaryInteger/shift: up(Shift)", + Tag.List.tags(.generic, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func up(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + try whereIs(type) + + func whereIs(_ type: T.Type) throws where T: BinaryInteger { + let size = IX(size: T.self) ?? 256 - if let size = IX(size: A.self), let flush = B.exactly(size).optional() { - for increment in B.zero ..< 4 { - let distance = flush + increment - Test().upshift(a0, distance, a0) - Test().upshift(a1, distance, a0) + for _ in 0 ..< conditional(debug: 32, release: 1024) { + let s = IX.random(in: 0...size-1, using: &(randomness)) + let a = T.entropic(size: size-s*IX(Bit(T.isArbitrary)), using: &randomness) + let b = a.up(Shift(Count(s))) + + if T.isArbitrary { + try #require(a.entropy() <= Count(size)) + try #require(b.entropy() <= Count(size)) + } + + try withOnlyOneCallToRequire((a, s, b)) { require in + a.withUnsafeBinaryIntegerElements(as: U8.self) { a in + b.withUnsafeBinaryIntegerElements(as: U8.self) { b in + for (i, j) in zip(-s..(_ type: T.Type, _ other: U.Type) throws where T: SystemsInteger, U: BinaryInteger { + for _ in 0 ..< conditional(debug: 32, release: 128) { + let (random) = T.entropic(through: Shift.max(or: 255), using: &randomness) + let distance = U.entropic(through: Shift.max(or: 255), using: &randomness) + + let up = random.up (Shift(masking: distance)) + let down = random.down(Shift(masking: distance)) + + try #require(reduce(random, &<<, distance) == up) + try #require(reduce(random, &<<=, distance) == up) + try #require(reduce(random, &>>, distance) == down) + try #require(reduce(random, &>>=, distance) == down) } } } - /// - Note: The systems integer constraint adds masking shift tests. - func testUpshiftRepeatingBitByGenericDistancesAsSystemsInteger() { - func whereIs(value: A.Type, distance: B.Type) where A: SystemsInteger, B: BinaryInteger { - //=----------------------------------= - let a0 = A(repeating: Bit.zero) - let a1 = A(repeating: Bit.one ) - //=----------------------------------= - for distance: B in (-4 as IX ..< 4).lazy.map(B.init(load:)) { - Test().upshift(a0, distance, a0) - } + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + @Test( + "BinaryInteger/shift/conveniences: down(Shift) vs positive distance in ±[0, size)", + Tag.List.tags(.generic, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func downVersusPositiveDistanceFromZeroUpToSize(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + for distance in typesAsBinaryInteger { + try whereIs(type, distance) + } + + func whereIs(_ type: T.Type, _ other: U.Type) throws where T: BinaryInteger, U: BinaryInteger { + let size = IX(size: T.self) ?? 256 + let clamped = IX(U(clamping: size - 1)) - always: do { - Test().upshift(a1, 0 as B, a1 &* 1) - Test().upshift(a1, 1 as B, a1 &* 2) - Test().upshift(a1, 2 as B, a1 &* 4) - Test().upshift(a1, 3 as B, a1 &* 8) + for _ in 0 ..< conditional(debug: 32, release: 128) { + let distance = IX.random(in: 0...clamped, using: &randomness) + let random = T.entropic(size: (((size))), using: &randomness) + let expectation = random.down(Shift(Count(distance))) + try #require(expectation == reduce(random, >>, U(distance))) + try #require(expectation == reduce(random, >>=, U(distance))) } + } + } + + @Test( + "BinaryInteger/shift/conveniences: down(Shift) vs negative distance in ±[0, size)", + Tag.List.tags(.generic, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func downVersusNegativeDistanceFromZeroUpToSize(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + for distance in typesAsBinaryIntegerAsSigned { + try whereIs(type, distance) + } + + func whereIs(_ type: T.Type, _ other: U.Type) throws where T: BinaryInteger, U: SignedInteger { + let size = IX(size: T.self) ?? 256 + let clamped = IX(U(clamping: size - 1)) - if B.isSigned { - Test().upshift(a1, ~0 as B, Bool(a1.appendix) ? a1 : a1 / 2) - Test().upshift(a1, ~1 as B, Bool(a1.appendix) ? a1 : a1 / 4) - Test().upshift(a1, ~2 as B, Bool(a1.appendix) ? a1 : a1 / 8) - Test().upshift(a1, ~3 as B, Bool(a1.appendix) ? a1 : a1 / 16) + for _ in 0 ..< conditional(debug: 32, release: 128) { + let distance = IX.random(in: 0...clamped, using: &randomness) + let random = T.entropic(size: (((size))), using: &randomness) + let expectation = random.down(Shift(Count(distance))) + try #require(expectation == reduce(random, <<, U(-distance))) + try #require(expectation == reduce(random, <<=, U(-distance))) } + } + } + + @Test( + "BinaryInteger/shift/conveniences: up(Shift) vs positive distance in ±[0, size)", + Tag.List.tags(.generic, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func upVersusPositiveDistanceFromZeroUpToSize(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + for distance in typesAsBinaryInteger { + try whereIs(type, distance) + } + + func whereIs(_ type: T.Type, _ other: U.Type) throws where T: BinaryInteger, U: BinaryInteger { + let size = IX(size: T.self) ?? 256 + let clamped = IX(U(clamping: size - 1)) + let arbitrary = IX(Bit(T.isArbitrary)) - if !B.isSigned, A.size <= Swift.max(B.size, Count(255 - 3)) { - Test().upshift(a1, ~0 as B, a0) // distance >= U8.max - 0 - Test().upshift(a1, ~1 as B, a0) // distance >= U8.max - 1 - Test().upshift(a1, ~2 as B, a0) // distance >= U8.max - 2 - Test().upshift(a1, ~3 as B, a0) // distance >= U8.max - 3 + for _ in 0 ..< conditional(debug: 32, release: 128) { + let distance = IX.random(in: 0...clamped, using: &randomness) + let random = T.entropic(size: size-distance*arbitrary, using: &randomness) + let expectation = random.up(Shift(Count(distance))) + try #require(expectation == reduce(random, <<, U(distance))) + try #require(expectation == reduce(random, <<=, U(distance))) } + } + } + + @Test( + "BinaryInteger/shift/conveniences: up(Shift) vs negative distance in ±[0, size)", + Tag.List.tags(.generic, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func upVersusNegativeDistanceFromZeroUpToSize(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + for distance in typesAsBinaryIntegerAsSigned { + try whereIs(type, distance) + } + + func whereIs(_ type: T.Type, _ other: U.Type) throws where T: BinaryInteger, U: SignedInteger { + let size = IX(size: T.self) ?? 256 + let clamped = IX(U(clamping: size - 1)) + let arbitrary = IX(Bit(T.isArbitrary)) - if let size = IX(size: A.self), let flush = B.exactly(size).optional() { - for increment in B.zero ..< 4 { - let distance = flush + increment - Test().upshift(a0, distance, a0) - Test().upshift(a1, distance, a0) - } + for _ in 0 ..< conditional(debug: 32, release: 128) { + let distance = IX.random(in: 0...clamped, using: &randomness) + let random = T.entropic(size: size-distance*arbitrary, using: &randomness) + let expectation = random.up(Shift(Count(distance))) + try #require(expectation == reduce(random, >>, U(-distance))) + try #require(expectation == reduce(random, >>=, U(-distance))) } } + } +} + +//*============================================================================* +// MARK: * Binary Integer x Shift x Edge Cases +//*============================================================================* + +@Suite struct BinaryIntegerTestsOnShiftEdgeCases { + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + @Test( + "BinaryInteger/shift/edge-cases: distance of zero yields input", + Tag.List.tags(.generic, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func distanceOfZeroYieldsInput(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + try whereIs(type) - for value in typesAsSystemsInteger { - for distance in typesAsBinaryInteger { - whereIs(value: value, distance: distance) + func whereIs(_ type: T.Type) throws where T: BinaryInteger { + for _ in 0 ..< 32 { + let random = T.entropic(through: Shift.max(or: 255), using: &randomness) + try #require(random == random.up (Count.zero)) + try #require(random == random.down(Count.zero)) + try #require(random == random.up (Shift.min )) + try #require(random == random.down(Shift.min )) } } } - func testDownshiftRepeatingBitByGenericDistancesAsArbitraryInteger() { - func whereIs(value: A.Type, distance: B.Type) where A: ArbitraryInteger, B: BinaryInteger { - //=----------------------------------= - let a0 = A(repeating: Bit.zero) - let a1 = A(repeating: Bit.one ) - //=----------------------------------= - for distance: B in (-4 as IX ..< 4).lazy.map(B.init(load:)) { - Test().downshift(a0, distance, a0) - } - - always: do { - Test().downshift(a1, 0 as B, Bool(a1.appendix) ? a1 : a1 / 1) - Test().downshift(a1, 1 as B, Bool(a1.appendix) ? a1 : a1 / 2) - Test().downshift(a1, 2 as B, Bool(a1.appendix) ? a1 : a1 / 4) - Test().downshift(a1, 3 as B, Bool(a1.appendix) ? a1 : a1 / 8) - } + @Test( + "BinaryInteger/shift/edge-cases: down by distance near nonappendix count", + Tag.List.tags(.generic, .important, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func downByDistanceNearNonappendixCount(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + try whereIs(type) + + func whereIs(_ type: T.Type) throws where T: BinaryInteger { + for _ in 0 ..< 256 { + let random = T.entropic(through: Shift.max(or: 255), using: &randomness) + let nonappendix = IX(raw: random.nondescending(random.appendix)) + let overshifted = T(repeating: random.appendix) - if B.isSigned { - Test().downshift(a1, ~0 as B, a1 &* 2) - Test().downshift(a1, ~1 as B, a1 &* 4) - Test().downshift(a1, ~2 as B, a1 &* 8) - Test().downshift(a1, ~3 as B, a1 &* 16) + if let distance = Count.exactly(nonappendix - 1)?.optional() { + try #require(random.down(distance) == (overshifted ^ 1)) + } + + try #require(random.down(Count(nonappendix )) == overshifted) + try #require(random.down(Count(nonappendix + 1)) == overshifted) } - - if !B.isSigned, A.size <= Swift.max(B.size, Count(255 - 3)) { - Test().downshift(a1, ~0 as B, A(repeating: a1.appendix)) // distance >= U8.max - 0 - Test().downshift(a1, ~1 as B, A(repeating: a1.appendix)) // distance >= U8.max - 1 - Test().downshift(a1, ~2 as B, A(repeating: a1.appendix)) // distance >= U8.max - 2 - Test().downshift(a1, ~3 as B, A(repeating: a1.appendix)) // distance >= U8.max - 3 + } + } + + @Test( + "BinaryInteger/shift/edge-cases: up by distance to start of next element", + Tag.List.tags(.generic, .important, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func upByDistanceToStartOfNextElement(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + try whereIs(type) + + func whereIs(_ type: T.Type) throws where T: BinaryInteger { + for _ in 0 ..< conditional(debug: 8, release: 32) { + let random = T.entropic(through: Shift.max(or: 255), using: &randomness) + var expectation = random + + for distance in 0 ... IX(size:T.Element.self) { + try #require((expectation) == random.up(Count(distance))) + expectation = expectation.plus(expectation).value + } } + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x |distance| > (size) is overshift + //=------------------------------------------------------------------------= + + @Test( + "BinaryInteger/shift/edge-cases: overshift by Count or Shift in ±[size, IX.max]", + Tag.List.tags(.generic, .random), + arguments: typesAsSystemsInteger, fuzzers + ) func overshiftByCountOrShiftFromSizeThroughLimit(type: any SystemsInteger.Type, randomness: consuming FuzzerInt) throws { + try whereIs(type) + + func whereIs(_ type: T.Type) throws where T: SystemsInteger { + let size = IX(size: T.self) - if let size = IX(size: A.self), let flush = B.exactly(size).optional() { - for increment in B.zero ..< 4 { - let distance = flush + increment - Test().downshift(a0, distance, A(repeating: a0.appendix)) - Test().downshift(a1, distance, A(repeating: a1.appendix)) + for _ in 0 ..< conditional(debug: 8, release: 32) { + let random = T.entropic(through: Shift.max(or: 255), using: &randomness) + let distance = Count(raw: IX.random(in: size...IX.max, using: &randomness)) + + try #require(random.up (Count(raw: distance)).isZero) + try #require(random.down(Count(raw: distance)) == T(repeating: random.appendix)) + + if let distance = Shift(exactly: distance) { + try #require(random.up (distance).isZero) + try #require(random.down(distance) == T(repeating: random.appendix)) } } } + } + + @Test( + "BinaryInteger/shift/edge-cases: overshift by positive distance in ±[size, IX.max]", + Tag.List.tags(.generic, .random), + arguments: typesAsSystemsInteger, fuzzers + ) func overshiftByPositiveDistanceFromSizeThroughLimit(type: any SystemsInteger.Type, randomness: consuming FuzzerInt) throws { + for distance in typesAsBinaryInteger { + try whereIs(type, distance) + } - for value in typesAsArbitraryInteger { - for distance in typesAsBinaryInteger { - whereIs(value: value, distance: distance) + func whereIs(_ type: T.Type, _ other: U.Type) throws where T: SystemsInteger, U: BinaryInteger { + guard let min = U.exactly(IX(size: T.self)).optional() else { return } + let max = U(clamping: IX.max) + + for _ in 0 ..< conditional(debug: 8, release: 32) { + let random = T.entropic(through: Shift.max(or: 255), using: &randomness) + let distance = U.random(in: min...max, using: &randomness) + + try #require(distance.isPositive) + try #require(distance.magnitude() >= IX(size: T.self)) + try #require(distance.magnitude() <= IX.max) + try #require((random << distance).isZero) + try #require((random >> distance) == T(repeating: random.appendix)) } } } - /// - Note: The systems integer constraint adds masking shift tests. - func testDownshiftRepeatingBitByGenericDistancesAsSystemsInteger() { - func whereIs(value: A.Type, distance: B.Type) where A: SystemsInteger, B: BinaryInteger { - //=----------------------------------= - let a0 = A(repeating: Bit.zero) - let a1 = A(repeating: Bit.one ) - //=----------------------------------= - for distance: B in (-4 as IX ..< 4).lazy.map(B.init(load:)) { - Test().downshift(a0, distance, a0) - } + @Test( + "BinaryInteger/shift/edge-cases: overshift by negative distance in ±[size, IX.max]", + Tag.List.tags(.generic, .random), + arguments: typesAsSystemsInteger, fuzzers + ) func overshiftByNegativeDistanceFromSizeThroughLimit(type: any SystemsInteger.Type, randomness: consuming FuzzerInt) throws { + for distance in typesAsBinaryInteger { + try whereIs(type, distance) + } + + func whereIs(_ type: T.Type, _ other: U.Type) throws where T: SystemsInteger, U: BinaryInteger { + guard let max = U.exactly(-IX(size: T.self)).optional() else { return } + let min = U(clamping: -IX.max) - always: do { - Test().downshift(a1, 0 as B, Bool(a1.appendix) ? a1 : a1 / 1) - Test().downshift(a1, 1 as B, Bool(a1.appendix) ? a1 : a1 / 2) - Test().downshift(a1, 2 as B, Bool(a1.appendix) ? a1 : a1 / 4) - Test().downshift(a1, 3 as B, Bool(a1.appendix) ? a1 : a1 / 8) - } + for _ in 0 ..< conditional(debug: 8, release: 32) { + let random = T.entropic(through: Shift.max(or: 255), using: &randomness) + let distance = U.random(in: min...max, using: &randomness) - if B.isSigned { - Test().downshift(a1, ~0 as B, a1 &* 2) - Test().downshift(a1, ~1 as B, a1 &* 4) - Test().downshift(a1, ~2 as B, a1 &* 8) - Test().downshift(a1, ~3 as B, a1 &* 16) - } - - if !B.isSigned, A.size <= Swift.max(B.size, Count(255 - 3)) { - Test().downshift(a1, ~0 as B, A(repeating: a1.appendix)) // distance >= U8.max - 0 - Test().downshift(a1, ~1 as B, A(repeating: a1.appendix)) // distance >= U8.max - 1 - Test().downshift(a1, ~2 as B, A(repeating: a1.appendix)) // distance >= U8.max - 2 - Test().downshift(a1, ~3 as B, A(repeating: a1.appendix)) // distance >= U8.max - 3 + try #require(distance.isNegative) + try #require(distance.magnitude() >= IX(size: T.self)) + try #require(distance.magnitude() <= IX.max) + try #require((random << distance) == T(repeating: random.appendix)) + try #require((random >> distance).isZero) } + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x |distance| > IX.max is overshift (by protocol) + //=------------------------------------------------------------------------= + + @Test( + "BinaryInteger/shift/edge-cases: overshift by positive distance in ±(IX.max, ∞)", + Tag.List.tags(.generic, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func overshiftByPositiveDistanceGreaterThanLimit(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + for distance in typesAsBinaryInteger { + try whereIs(type, distance) + } + + func whereIs(_ type: T.Type, _ other: U.Type) throws where T: BinaryInteger, U: BinaryInteger { + guard let min = U.exactly(UX.msb).optional() else { return } + let max = U(clamping: IXL(Array(repeating: U64.max, count: 4))) - if let size = IX(size: A.self), let flush = B.exactly(size).optional() { - for increment in B.zero ..< 4 { - let distance = flush + increment - Test().downshift(a0, distance, A(repeating: a0.appendix)) - Test().downshift(a1, distance, A(repeating: a1.appendix)) - } + for _ in 0 ..< conditional(debug: 8, release: 32) { + let random = T.entropic(through: Shift.max(or: 255), using: &randomness) + let distance = U.random(in: min...max, using: &randomness) + + try #require(distance.isInfinite == false) + try #require(distance.magnitude() > IX.max) + try #require((random << distance).isZero) + try #require((random >> distance) == T(repeating: random.appendix)) } } + } + + @Test( + "BinaryInteger/shift/edge-cases: overshift by negative distance in ±(IX.max, ∞)", + Tag.List.tags(.generic, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func overshiftByNegativeDistanceGreaterThanLimit(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + for distance in typesAsBinaryInteger { + try whereIs(type, distance) + } - for value in typesAsSystemsInteger { - for distance in typesAsBinaryInteger { - whereIs(value: value, distance: distance) + func whereIs(_ type: T.Type, _ other: U.Type) throws where T: BinaryInteger, U: BinaryInteger { + guard let max = U.exactly(IX.min).optional() else { return } + let min = U(clamping:-IXL(Array(repeating: U64.max, count: 4))) + + for _ in 0 ..< conditional(debug: 8, release: 32) { + let random = T.entropic(through: Shift.max(or: 255), using: &randomness) + let distance = U.random(in: min...max, using: &randomness) + + try #require(distance.isInfinite == false) + try #require(distance.magnitude() > IX.max) + try #require((random << distance) == T(repeating: random.appendix)) + try #require((random >> distance).isZero) } } } //=------------------------------------------------------------------------= - // MARK: Tests + // MARK: Tests x |distance| > IX.max is overshift (by protocol) //=------------------------------------------------------------------------= - func testSmartShiftByMoreThanSizeIsFlush() { - func whereIs(value: A.Type, distance: B.Type) where A: SystemsInteger, B: ArbitraryInteger { - for base: A in (-4 as IX ..< 4).lazy.map(A.init(load:)) { - for increment: B in 1 ..< 4 { - let distance = B(IX(size: A.self)) + increment - - always: do { - Test() .upshift(base, distance, A(repeating: Bit.zero)) - Test().downshift(base, distance, A(repeating: base.appendix)) - } - - if let distance = distance.negated().optional() { - Test() .upshift(base, distance, A(repeating: base.appendix)) - Test().downshift(base, distance, A(repeating: Bit.zero)) - } + @Test( + "BinaryInteger/shift/edge-cases: overshift by infinite Count or Shift", + Tag.List.tags(.generic, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func overshiftByInfiniteCountOrShift(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + try whereIs(type) + + func whereIs(_ type: T.Type) throws where T: BinaryInteger { + for _ in 0 ..< 32 { + let random = T.entropic(through: Shift.max(or: 255), using: &randomness) + let distance = Count(raw: IX.random(in: IX.negatives, using: &randomness)!) + + try #require(distance.isInfinite) + try #require(random.up (Count(raw: distance)).isZero) + try #require(random.down(Count(raw: distance)) == T(repeating: random.appendix)) + + if let distance = Shift(exactly: distance) { + try #require(T.isArbitrary) + try #require(distance.isInfinite) + try #require(random.up (distance).isZero) + try #require(random.down(distance) == T(repeating: random.appendix)) } } } - - for value in typesAsSystemsInteger { - for distance in typesAsArbitraryInteger { - whereIs(value: value, distance: distance) + } + + @Test( + "BinaryInteger/shift/edge-cases: overshift by infinite ArbitraryInteger", + Tag.List.tags(.generic, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func overshiftByInfiniteArbitraryInteger(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + for distance in typesAsArbitraryIntegerAsUnsigned { + try whereIs(type, distance) + } + + func whereIs(_ type: T.Type, _ other: U.Type) throws where T: BinaryInteger, U: ArbitraryIntegerAsUnsigned { + for _ in 0 ..< 32 { + let random = T.entropic(through: Shift.max(or: 255), using: &randomness) + let distance = U.entropic(through: Shift.max(or: 255), as: Domain.natural, using: &randomness).toggled() + + try #require(distance.isInfinite) + try #require((random << distance).isZero) + try #require((random >> distance) == T(repeating: random.appendix)) } } } +} + +//*============================================================================* +// MARK: * Binary Integer x Shift x Disambiguation +//*============================================================================* + +@Suite(.tags(.disambiguation)) struct BinaryIntegerTestsOnShiftDisambiguation { - func testSmartShiftByMoreThanMaxSignedWordIsFlush() { - func whereIs(value: A.Type, distance: B.Type) where A: BinaryInteger, B: ArbitraryInteger { - for base: A in (-4 as IX ..< 4).lazy.map(A.init(load:)) { - for increment: B in 1 ..< 4 { - let distance = B(IX.max) + increment - - always: do { - Test() .upshift(base, distance, A(repeating: Bit.zero)) - Test().downshift(base, distance, A(repeating: base.appendix)) - } - - if let distance = distance.negated().optional() { - Test() .upshift(base, distance, A(repeating: base.appendix)) - Test().downshift(base, distance, A(repeating: Bit.zero)) - } - } - } + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + @Test( + "BinaryInteger/exponentiation/disambiguation: literals", + Tag.List.tags(.generic) + ) func literals() { + func build(_ x: inout T) where T: BinaryInteger { + x <<= 0 + x >>= 0 + + _ = x << 0 + _ = x >> 0 } - for value in typesAsBinaryInteger { - for distance in typesAsArbitraryInteger { - whereIs(value: value, distance: distance) - } + func build(_ x: inout T) where T: SystemsInteger { + x <<= 0 + x &<<= 0 + x >>= 0 + x &>>= 0 + + _ = x << 0 + _ = x &<< 0 + _ = x >> 0 + _ = x &>> 0 } } - func testSmartShiftIsLikeWrappingProductOrQuotientAsSystemsInteger() { - func whereIs(value: T.Type) where T: SystemsInteger { - var instance = T.lsb - - shift: while !instance.isZero { - var multiplier = Fallible(T.lsb) + @Test( + "BinaryInteger/exponentiation/disambiguation: smart shift by IX vs Swift.Int", + Tag.List.tags(.generic, .random), + arguments: typesAsBinaryInteger, fuzzers + ) func smartByTokenVersusSwiftToken(type: any BinaryInteger.Type, randomness: consuming FuzzerInt) throws { + try whereIs(type) - for distance in IX.zero ..< IX(size: T.self) { - let product = instance &* multiplier.value - var quotient = distance.isZero ? instance : instance / multiplier.value - - if multiplier.error { - Test().yay (T.isSigned) - Test().same(multiplier.value, T.msb) - quotient = quotient.negated().unwrap() - } - - Test() .upshift(instance, distance, product) - Test().downshift(instance, distance, quotient) - multiplier = multiplier.map({ $0.times(2) }) + func whereIs(_ type: T.Type) throws where T: BinaryInteger { + for _ in 0 ..< 32 { + var distance = IX.entropic(using: &randomness) + let random = T.entropic(through: Shift.max(or: 255), using: &randomness) + + if T.isArbitrary { + distance = IX.random(in: -256...256) } - instance = instance.times(2).value // << 1 + try #require(reduce(random, <<, distance) == reduce(random, <<, Swift.Int(distance))) + try #require(reduce(random, <<=, distance) == reduce(random, <<=, Swift.Int(distance))) + try #require(reduce(random, >>, distance) == reduce(random, >>, Swift.Int(distance))) + try #require(reduce(random, >>=, distance) == reduce(random, >>=, Swift.Int(distance))) } } + } + + @Test( + "BinaryInteger/exponentiation/disambiguation: masking swift as IX vs Swift.Int", + Tag.List.tags(.generic, .random), + arguments: typesAsSystemsInteger, fuzzers + ) func maskingByTokenVersusSwiftToken(type: any SystemsInteger.Type, randomness: consuming FuzzerInt) throws { + try whereIs(type) - for value in typesAsCoreInteger { - whereIs(value: value) + func whereIs(_ type: T.Type) throws where T: SystemsInteger { + for _ in 0 ..< 32 { + let distance = IX.entropic(using: &randomness) + let random = T.entropic(through: Shift.max(or: 255), using: &randomness) + + try #require(reduce(random, &<<, distance) == reduce(random, &<<, Swift.Int(distance))) + try #require(reduce(random, &<<=, distance) == reduce(random, &<<=, Swift.Int(distance))) + try #require(reduce(random, &>>, distance) == reduce(random, &>>, Swift.Int(distance))) + try #require(reduce(random, &>>=, distance) == reduce(random, &>>=, Swift.Int(distance))) + } } - - whereIs(value: DoubleInt.self) - whereIs(value: DoubleInt.self) } }