Skip to content

Commit

Permalink
Some init(clamping:) infinity fixes (#21).
Browse files Browse the repository at this point in the history
  • Loading branch information
oscbyspro committed Jun 20, 2024
1 parent 5f132b2 commit d1a340c
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 18 deletions.
32 changes: 19 additions & 13 deletions Sources/CoreKit/BinaryInteger+Validation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ extension BinaryInteger {
}

/// Creates a new instance by clamping the given `source`.
@_disfavoredOverload // req. because of EdgyInteger.init(clamping: some FiniteInteger)
@_disfavoredOverload // BinaryInteger.init(clamping: some FiniteInteger)
@inlinable public init(clamping source: some BinaryInteger) where Self: EdgyInteger {
self.init(clamping: source)!
}
Expand All @@ -149,25 +149,31 @@ extension BinaryInteger {
///
/// - Note: This is the most generic version of `init(clamping:)`.
///
@_disfavoredOverload // BinaryInteger.init(clamping: some FiniteInteger)
@inlinable public init?(clamping source: some BinaryInteger) {
if Self.isSigned, source.isInfinite {
let size: Magnitude = Self.size
if !size.isInfinite {

if let instance = Self.exactly(source).optional() {
self = instance

} else if Self.isSigned {
let distance = (size).decremented().unchecked()
let msb = (1 as Magnitude).up(Shift(unchecked: distance))
self.init(raw: source.isNegative ? msb : msb.toggled())

} else {
self.init(repeating: Bit(!source.isNegative))
}

} else if Self.isSigned, source.isInfinite {
return nil

} else if !Self.isSigned, source.isNegative {
self.init()

} else if Self.size.isInfinite {
} else {
self.init(load: source)

} else if let instance = Self.exactly(source).optional() {
self = instance

} else if Self.isSigned {
let msb = (1 as Magnitude).up(Shift(Self.size - 1))
self.init(raw: source.isNegative ? msb : msb.toggled())

} else/* if !Self.isSigned */ {
self.init(repeating: Bit.one)
}
}
}
4 changes: 0 additions & 4 deletions Sources/TestKit/Globals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ public let coreSystemsIntegersWhereIsUnsigned: [any (SystemsInteger & UnsignedIn
UX.self, U8.self, U16.self, U32.self, U64.self,
]

//=----------------------------------------------------------------------------=
// MARK: + Values
//=----------------------------------------------------------------------------=

/// A collection of all primes that fit in one byte.
///
/// - Note: It contains `54` elements.
Expand Down
4 changes: 3 additions & 1 deletion Sources/TestKit/Test+Validation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ extension Test {
yay(clamped.incremented().error, "T.init(clamping:) - max")
}
} else {
yay(Output.isSigned && input.isInfinite, "arbitrary signed integers cannot clamp infinite values")
yay(Output.isSigned, "init(clamping:) [nil][0]")
yay(Output.size.isInfinite, "init(clamping:) [nil][1]")
yay((((input))).isInfinite, "init(clamping:) [nil][2]")
}
//=--------------------------------------=
// path: sign and magnitude
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
42 changes: 42 additions & 0 deletions Tests/UltimathnumTests/BinaryInteger+Validation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//=----------------------------------------------------------------------------=
// 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 InfiniIntKit
import TestKit

//*============================================================================*
// MARK: * Binary Integer x Validation
//*============================================================================*
//=----------------------------------------------------------------------------=
// MARK: + Edge Cases
//=----------------------------------------------------------------------------=

extension BinaryIntegerTests {

//=------------------------------------------------------------------------=
// MARK: Tests
//=------------------------------------------------------------------------=

/// 2024-06-20: Signed systems integers should successfully clamp `∞`.
func testSystemsIntegersCanClampInfiniteValues() {
func whereIs<A, B>(_ source: A.Type, _ destinaiton: B.Type) where A: UnsignedInteger, B: SystemsInteger {
precondition(A.size.isInfinite)
Test().same(B(clamping: A.max ), B.max)
Test().same(B(clamping: A.max - 1), B.max)
}

for source in Self.arbitraryIntegersWhereIsUnsigned {
for destinaiton in Self.systemsIntegers {
whereIs(source, destinaiton)
}
}
}
}
66 changes: 66 additions & 0 deletions Tests/UltimathnumTests/BinaryInteger.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//=----------------------------------------------------------------------------=
// 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 InfiniIntKit
import TestKit

//*============================================================================*
// MARK: * Binary Integer
//*============================================================================*

final class BinaryIntegerTests: XCTestCase {

//=------------------------------------------------------------------------=
// MARK: Metadata
//=------------------------------------------------------------------------=

static let types: [any BinaryInteger.Type] = {
typesWhereIsSigned +
typesWhereIsUnsigned
}()

static let typesWhereIsSigned: [any SignedInteger.Type] = {
systemsIntegersWhereIsSigned +
arbitraryIntegersWhereIsSigned
}()

static let typesWhereIsUnsigned: [any UnsignedInteger.Type] = {
systemsIntegersWhereIsUnsigned +
arbitraryIntegersWhereIsUnsigned
}()

static let arbitraryIntegersWhereIsSigned: [any SignedInteger.Type] = [
InfiniInt<I8>.self,
InfiniInt<IX>.self,
]

static let arbitraryIntegersWhereIsUnsigned: [any UnsignedInteger.Type] = [
InfiniInt<U8>.self,
InfiniInt<UX>.self,
]

static var systemsIntegers: [any SystemsInteger.Type] = {
systemsIntegersWhereIsSigned +
systemsIntegersWhereIsUnsigned
}()

static var systemsIntegersWhereIsSigned: [any (SystemsInteger & SignedInteger).Type] = [
IX.self, I8 .self, I16.self, I32.self, I64 .self,
DoubleInt<I8>.self, DoubleInt<DoubleInt<I8>>.self,
DoubleInt<IX>.self, DoubleInt<DoubleInt<IX>>.self,
]

static var systemsIntegersWhereIsUnsigned: [any (SystemsInteger & UnsignedInteger).Type] = [
UX.self, U8 .self, U16.self, U32.self, U64 .self,
DoubleInt<U8>.self, DoubleInt<DoubleInt<U8>>.self,
DoubleInt<UX>.self, DoubleInt<DoubleInt<UX>>.self,
]
}

0 comments on commit d1a340c

Please sign in to comment.