From 2f99176b442c4a7443b4e6e003445423245894c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Bystr=C3=B6m=20Ericsson?= Date: Sun, 25 Aug 2024 07:50:07 +0200 Subject: [PATCH] Interoperable core integers (#74). --- Sources/CoreKit/Models/CoreInt.swift | 169 +++++++++++------- .../BinaryInteger+Stdlib.swift | 68 +++++++ 2 files changed, 172 insertions(+), 65 deletions(-) create mode 100644 Tests/UltimathnumTests/BinaryInteger+Stdlib.swift diff --git a/Sources/CoreKit/Models/CoreInt.swift b/Sources/CoreKit/Models/CoreInt.swift index 5182051d..dbe99fb1 100644 --- a/Sources/CoreKit/Models/CoreInt.swift +++ b/Sources/CoreKit/Models/CoreInt.swift @@ -30,21 +30,20 @@ /// - `U32` /// - `U64` /// -@usableFromInline protocol CoreInteger: SystemsInteger where -BitPattern == Stdlib.BitPattern, Element == Self, Signitude: CoreInteger, -Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { - - associatedtype Stdlib: Swift.FixedWidthInteger & BitCastable & Sendable - - //=------------------------------------------------------------------------= - // MARK: Initializers - //=------------------------------------------------------------------------= - - @inlinable init(_ source: Stdlib) - - //=------------------------------------------------------------------------= - // MARK: Utilities - //=------------------------------------------------------------------------= +@usableFromInline protocol CoreInteger: + Interoperable, + SystemsInteger +where + BitPattern == Stdlib.BitPattern, + Element == Self, + IntegerLiteralType == Stdlib, + Signitude: CoreInteger, + Stdlib: BitCastable, + Stdlib: Swift.FixedWidthInteger, + Stdlib: Swift.Sendable, + Magnitude: CoreInteger, + Magnitude.Stdlib == Stdlib.Magnitude +{ @inlinable var base: Stdlib { get } } @@ -65,9 +64,9 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { /// A pointer-bit signed binary integer. @frozen public struct IX: CoreIntegerWhereIsSigned, CoreIntegerWhereIsNotByte { - @usableFromInline typealias Stdlib = Swift.Int + public typealias Stdlib = Swift.Int - public typealias BitPattern = Swift.Int.BitPattern + public typealias BitPattern = Stdlib.BitPattern public typealias Element = Self @@ -85,17 +84,21 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { // MARK: Initializers //=------------------------------------------------------------------------= - @inlinable public init(_ source: Swift.Int) { + @inlinable public init(_ source: Stdlib) { self.base = source } - @inlinable public init(raw source: Swift.Int.BitPattern) { + @inlinable public init(raw source: BitPattern) { self.base = Stdlib(bitPattern: source) } - @inlinable public init(integerLiteral source: Swift.Int) { + @inlinable public init(integerLiteral source: Stdlib) { self.base = source } + + @inlinable public consuming func stdlib() -> Stdlib { + self.base + } } //*============================================================================* @@ -105,9 +108,9 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { /// An 8-bit signed binary integer. @frozen public struct I8: CoreIntegerWhereIsSigned, CoreIntegerWhereIsNotToken { - @usableFromInline typealias Stdlib = Swift.Int8 + public typealias Stdlib = Swift.Int8 - public typealias BitPattern = Swift.Int8.BitPattern + public typealias BitPattern = Stdlib.BitPattern public typealias Element = Self @@ -125,17 +128,21 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { // MARK: Initializers //=------------------------------------------------------------------------= - @inlinable public init(_ source: Swift.Int8) { + @inlinable public init(_ source: Stdlib) { self.base = source } - @inlinable public init(raw source: Swift.Int8.BitPattern) { + @inlinable public init(raw source: BitPattern) { self.base = Stdlib(bitPattern: source) } - @inlinable public init(integerLiteral source: Swift.Int8) { + @inlinable public init(integerLiteral source: Stdlib) { self.base = source } + + @inlinable public consuming func stdlib() -> Stdlib { + self.base + } } //*============================================================================* @@ -145,9 +152,9 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { /// A 16-bit signed binary integer. @frozen public struct I16: CoreIntegerWhereIsSigned, CoreIntegerWhereIsNotByte, CoreIntegerWhereIsNotToken { - @usableFromInline typealias Stdlib = Swift.Int16 + public typealias Stdlib = Swift.Int16 - public typealias BitPattern = Swift.Int16.BitPattern + public typealias BitPattern = Stdlib.BitPattern public typealias Element = Self @@ -165,17 +172,21 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { // MARK: Initializers //=------------------------------------------------------------------------= - @inlinable public init(_ source: Swift.Int16) { + @inlinable public init(_ source: Stdlib) { self.base = source } - @inlinable public init(raw source: Swift.Int16.BitPattern) { + @inlinable public init(raw source: BitPattern) { self.base = Stdlib(bitPattern: source) } - @inlinable public init(integerLiteral source: Swift.Int16) { + @inlinable public init(integerLiteral source: Stdlib) { self.base = source } + + @inlinable public consuming func stdlib() -> Stdlib { + self.base + } } //*============================================================================* @@ -185,9 +196,9 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { /// A 32-bit signed binary integer. @frozen public struct I32: CoreIntegerWhereIsSigned, CoreIntegerWhereIsNotByte, CoreIntegerWhereIsNotToken { - @usableFromInline typealias Stdlib = Swift.Int32 + public typealias Stdlib = Swift.Int32 - public typealias BitPattern = Swift.Int32.BitPattern + public typealias BitPattern = Stdlib.BitPattern public typealias Element = Self @@ -205,17 +216,21 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { // MARK: Initializers //=------------------------------------------------------------------------= - @inlinable public init(_ source: Swift.Int32) { + @inlinable public init(_ source: Stdlib) { self.base = source } - @inlinable public init(raw source: Swift.Int32.BitPattern) { + @inlinable public init(raw source: BitPattern) { self.base = Stdlib(bitPattern: source) } - @inlinable public init(integerLiteral source: Swift.Int32) { + @inlinable public init(integerLiteral source: Stdlib) { self.base = source } + + @inlinable public consuming func stdlib() -> Stdlib { + self.base + } } //*============================================================================* @@ -225,9 +240,9 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { /// A 64-bit signed binary integer. @frozen public struct I64: CoreIntegerWhereIsSigned, CoreIntegerWhereIsNotByte, CoreIntegerWhereIsNotToken { - @usableFromInline typealias Stdlib = Swift.Int64 + public typealias Stdlib = Swift.Int64 - public typealias BitPattern = Swift.Int64.BitPattern + public typealias BitPattern = Stdlib.BitPattern public typealias Element = Self @@ -245,17 +260,21 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { // MARK: Initializers //=------------------------------------------------------------------------= - @inlinable public init(_ source: Swift.Int64) { + @inlinable public init(_ source: Stdlib) { self.base = source } - @inlinable public init(raw source: Swift.Int64.BitPattern) { + @inlinable public init(raw source: BitPattern) { self.base = Stdlib(bitPattern: source) } - @inlinable public init(integerLiteral source: Swift.Int64) { + @inlinable public init(integerLiteral source: Stdlib) { self.base = source } + + @inlinable public consuming func stdlib() -> Stdlib { + self.base + } } //*============================================================================* @@ -265,9 +284,9 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { /// A pointer-bit unsigned binary integer. @frozen public struct UX: CoreIntegerWhereIsUnsigned, CoreIntegerWhereIsNotByte { - @usableFromInline typealias Stdlib = Swift.UInt + public typealias Stdlib = Swift.UInt - public typealias BitPattern = Swift.UInt.BitPattern + public typealias BitPattern = Stdlib.BitPattern public typealias Element = Self @@ -285,17 +304,21 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { // MARK: Initializers //=------------------------------------------------------------------------= - @inlinable public init(_ source: Swift.UInt) { + @inlinable public init(_ source: Stdlib) { self.base = source } - @inlinable public init(raw source: Swift.UInt.BitPattern) { + @inlinable public init(raw source: BitPattern) { self.base = source } - @inlinable public init(integerLiteral source: Swift.UInt) { + @inlinable public init(integerLiteral source: Stdlib) { self.base = source } + + @inlinable public consuming func stdlib() -> Stdlib { + self.base + } } //*============================================================================* @@ -305,9 +328,9 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { /// An 8-bit unsigned binary integer. @frozen public struct U8: CoreIntegerWhereIsUnsigned, CoreIntegerWhereIsNotToken { - @usableFromInline typealias Stdlib = Swift.UInt8 + public typealias Stdlib = Swift.UInt8 - public typealias BitPattern = Swift.UInt8.BitPattern + public typealias BitPattern = Stdlib.BitPattern public typealias Element = Self @@ -325,17 +348,21 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { // MARK: Initializers //=------------------------------------------------------------------------= - @inlinable public init(_ source: Swift.UInt8) { + @inlinable public init(_ source: Stdlib) { self.base = source } - @inlinable public init(raw source: Swift.UInt8.BitPattern) { + @inlinable public init(raw source: BitPattern) { self.base = source } - @inlinable public init(integerLiteral source: Swift.UInt8) { + @inlinable public init(integerLiteral source: Stdlib) { self.base = source } + + @inlinable public consuming func stdlib() -> Stdlib { + self.base + } } //*============================================================================* @@ -345,9 +372,9 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { /// A 16-bit unsigned binary integer. @frozen public struct U16: CoreIntegerWhereIsUnsigned, CoreIntegerWhereIsNotByte, CoreIntegerWhereIsNotToken { - @usableFromInline typealias Stdlib = Swift.UInt16 + public typealias Stdlib = Swift.UInt16 - public typealias BitPattern = Swift.UInt16.BitPattern + public typealias BitPattern = Stdlib.BitPattern public typealias Element = Self @@ -365,17 +392,21 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { // MARK: Initializers //=------------------------------------------------------------------------= - @inlinable public init(_ source: Swift.UInt16) { + @inlinable public init(_ source: Stdlib) { self.base = source } - @inlinable public init(raw source: Swift.UInt16.BitPattern) { + @inlinable public init(raw source: BitPattern) { self.base = source } - @inlinable public init(integerLiteral source: Swift.UInt16) { + @inlinable public init(integerLiteral source: Stdlib) { self.base = source } + + @inlinable public consuming func stdlib() -> Stdlib { + self.base + } } //*============================================================================* @@ -385,9 +416,9 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { /// A 32-bit unsigned binary integer. @frozen public struct U32: CoreIntegerWhereIsUnsigned, CoreIntegerWhereIsNotByte, CoreIntegerWhereIsNotToken { - @usableFromInline typealias Stdlib = Swift.UInt32 + public typealias Stdlib = Swift.UInt32 - public typealias BitPattern = Swift.UInt32.BitPattern + public typealias BitPattern = Stdlib.BitPattern public typealias Element = Self @@ -405,17 +436,21 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { // MARK: Initializers //=------------------------------------------------------------------------= - @inlinable public init(_ source: Swift.UInt32) { + @inlinable public init(_ source: Stdlib) { self.base = source } - @inlinable public init(raw source: Swift.UInt32.BitPattern) { + @inlinable public init(raw source: BitPattern) { self.base = source } - @inlinable public init(integerLiteral source: Swift.UInt32) { + @inlinable public init(integerLiteral source: Stdlib) { self.base = source } + + @inlinable public consuming func stdlib() -> Stdlib { + self.base + } } //*============================================================================* @@ -425,9 +460,9 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { /// A 64-bit unsigned binary integer. @frozen public struct U64: CoreIntegerWhereIsUnsigned, CoreIntegerWhereIsNotByte, CoreIntegerWhereIsNotToken { - @usableFromInline typealias Stdlib = Swift.UInt64 + public typealias Stdlib = Swift.UInt64 - public typealias BitPattern = Swift.UInt64.BitPattern + public typealias BitPattern = Stdlib.BitPattern public typealias Element = Self @@ -445,15 +480,19 @@ Magnitude: CoreInteger, Magnitude.Stdlib == Stdlib.Magnitude { // MARK: Initializers //=------------------------------------------------------------------------= - @inlinable public init(_ source: Swift.UInt64) { + @inlinable public init(_ source: Stdlib) { self.base = source } - @inlinable public init(raw source: Swift.UInt64.BitPattern) { + @inlinable public init(raw source: BitPattern) { self.base = source } - @inlinable public init(integerLiteral source: Swift.UInt64) { + @inlinable public init(integerLiteral source: Stdlib) { self.base = source } + + @inlinable public consuming func stdlib() -> Stdlib { + self.base + } } diff --git a/Tests/UltimathnumTests/BinaryInteger+Stdlib.swift b/Tests/UltimathnumTests/BinaryInteger+Stdlib.swift new file mode 100644 index 00000000..be4901e1 --- /dev/null +++ b/Tests/UltimathnumTests/BinaryInteger+Stdlib.swift @@ -0,0 +1,68 @@ +//=----------------------------------------------------------------------------= +// 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 RandomIntKit +import TestKit + +//*============================================================================* +// MARK: * Binary Integer x Stdlib +//*============================================================================* + +final class BinaryIntegerTestsOnStdlib: XCTestCase { + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testStdlib() { + func whereIs(_ type: T.Type, randomness: consuming FuzzerInt, line: UInt = #line) + where T: BinaryInteger, T: Interoperable, T.Stdlib: Swift.BinaryInteger { + + let test = Test(line: line) + let range = Esque.min...Esque.max + + for _ in 0..<16 { + var a = T.random(in: range, using: &randomness) + var b = T.random(in: range, using: &randomness) + let x = a + let y = b + + test.same(a, x) + test.same(b, y) + test.same(T(a.stdlib), x) + test.same(T(b.stdlib), y) + test.same(T(a.stdlib()), x) + test.same(T(b.stdlib()), y) + + a.stdlib ^= b.stdlib + b.stdlib ^= a.stdlib + a.stdlib ^= b.stdlib + + test.same(a, y) + test.same(b, x) + test.same(T(a.stdlib), y) + test.same(T(b.stdlib), x) + test.same(T(a.stdlib()), y) + test.same(T(b.stdlib()), x) + } + } + + whereIs( IX.self, randomness: fuzzer) + whereIs( UX.self, randomness: fuzzer) + whereIs( I8.self, randomness: fuzzer) + whereIs( U8.self, randomness: fuzzer) + whereIs(I16.self, randomness: fuzzer) + whereIs(U16.self, randomness: fuzzer) + whereIs(I32.self, randomness: fuzzer) + whereIs(U32.self, randomness: fuzzer) + whereIs(I64.self, randomness: fuzzer) + whereIs(U64.self, randomness: fuzzer) + } +}