Skip to content

Commit

Permalink
[NBKCoreKit] Sign and magnitude decoding (#86).
Browse files Browse the repository at this point in the history
  • Loading branch information
oscbyspro committed Sep 28, 2023
1 parent 7b6cf53 commit 906622f
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 83 deletions.
3 changes: 3 additions & 0 deletions Sources/NBKCoreKit/Aliases.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ public typealias PVO<PV> = (partialValue: PV, overflow: Bool)

/// A quotient and a remainder, relating to division.
public typealias QR<Q,R> = (quotient: Q, remainder: R)

/// A sign and a magnitude.
public typealias SM<M> = (sign: FloatingPointSign, magnitude: M)
95 changes: 86 additions & 9 deletions Sources/NBKCoreKit/Private/NBKIntegerDescription+Decoding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ extension NBK.IntegerDescription {
}

//=--------------------------------------------------------------------=
// MARK: Utilities
// MARK: Utilities x Binary Integer
//=--------------------------------------------------------------------=

@inlinable public func decode<T: NBKBinaryInteger>(
_ description: some StringProtocol, as type: T.Type = T.self) -> T? {
var description = String(description); return description.withUTF8({ self.decode($0) })
var description = String(description)
return description.withUTF8({ self.decode($0) })
}

@inlinable public func decode<T: NBKBinaryInteger>(
Expand All @@ -68,10 +69,48 @@ extension NBK.IntegerDescription {

@inlinable public func decode<T: NBKBinaryInteger>(
_ description: NBK.UnsafeUTF8, as type: T.Type = T.self) -> T? {
guard let components: SM<T.Magnitude> = self.decodeCodeBlock(description) else { return nil }
return T(sign: components.sign, magnitude: components.magnitude)
}

//=--------------------------------------------------------------------=
// MARK: Utilities x Sign & Magnitude
//=--------------------------------------------------------------------=

@inlinable public func decode<M: NBKUnsignedInteger>(
_ description: some StringProtocol, as type: SM<M>.Type = SM<M>.self) -> SM<M>? {
var description = String(description)
return description.withUTF8({ self.decode($0) })
}

@inlinable public func decode<M: NBKUnsignedInteger>(
_ description: StaticString, as type: SM<M>.Type = SM<M>.self) -> SM<M>? {
description.withUTF8Buffer({ self.decode($0) })
}

@inlinable public func decode<M: NBKUnsignedInteger>(
_ description: NBK.UnsafeUTF8, as type: SM<M>.Type = SM<M>.self) -> SM<M>? {
self.decodeCodeBlock(description)
}

//=--------------------------------------------------------------------=
// MARK: Utilities x Private x Algorithms
//=--------------------------------------------------------------------=

/// ### Development 1
///
/// Consider throwing errors instead of returning optionals.
///
/// ### Development 2
///
/// `@inline(always)` is required for performance reasons (with optionals, not errors).
///
@inline(__always) @inlinable func decodeCodeBlock<M: NBKUnsignedInteger>(
_ description: NBK.UnsafeUTF8, as type: SM<M>.Type = SM<M>.self) -> SM<M>? {
let components = NBK.IntegerDescription.makeSignBody(from: description)
let digits = NBK.UnsafeUTF8(rebasing: components.body)
guard let magnitude: T.Magnitude = NBK.IntegerDescription.decode(digits: digits, solution: self.solution) else { return nil }
return T(sign: components.sign, magnitude: magnitude)
guard let magnitude: M = NBK.IntegerDescription.decode(digits: digits, solution: self.solution) else { return nil }
return SM(sign: components.sign, magnitude: magnitude)
}
}

Expand Down Expand Up @@ -100,15 +139,15 @@ extension NBK.IntegerDescription {
/// - Note: The decoding strategy is case insensitive.
///
@frozen public struct DecoderDecodingRadix {

//=--------------------------------------------------------------------=
// MARK: Initializers
//=--------------------------------------------------------------------=

@inlinable public init() { }

//=--------------------------------------------------------------------=
// MARK: Utilities
// MARK: Utilities x Binary Integer
//=--------------------------------------------------------------------=

@inlinable public func decode<T: NBKBinaryInteger>(
Expand All @@ -124,11 +163,49 @@ extension NBK.IntegerDescription {

@inlinable public func decode<T: NBKBinaryInteger>(
_ description: NBK.UnsafeUTF8, as type: T.Type = T.self) -> T? {
guard let components: SM<T.Magnitude> = self.decodeCodeBlock(description) else { return nil }
return T(sign: components.sign, magnitude: components.magnitude)
}

//=--------------------------------------------------------------------=
// MARK: Utilities x Sign & Magnitude
//=--------------------------------------------------------------------=

@inlinable public func decode<M: NBKUnsignedInteger>(
_ description: some StringProtocol, as type: SM<M>.Type = SM<M>.self) -> SM<M>? {
var description = String(description)
return description.withUTF8({ self.decode($0) })
}

@inlinable public func decode<M: NBKUnsignedInteger>(
_ description: StaticString, as type: SM<M>.Type = SM<M>.self) -> SM<M>? {
description.withUTF8Buffer({ self.decode($0) })
}

@inlinable public func decode<M: NBKUnsignedInteger>(
_ description: NBK.UnsafeUTF8, as type: SM<M>.Type = SM<M>.self) -> SM<M>? {
self.decodeCodeBlock(description)
}

//=--------------------------------------------------------------------=
// MARK: Utilities x Private x Algorithms
//=--------------------------------------------------------------------=

/// ### Development 1
///
/// Consider throwing errors instead of returning optionals.
///
/// ### Development 2
///
/// `@inline(always)` is required for performance reasons (with optionals, not errors).
///
@inline(__always) @inlinable func decodeCodeBlock<M: NBKUnsignedInteger>(
_ description: NBK.UnsafeUTF8, as type: SM<M>.Type = SM<M>.self) -> SM<M>? {
let components = NBK.IntegerDescription.makeSignRadixBody(from: description)
let solution = AnyRadixSolution<UInt>(components.radix)
let digits = NBK.UnsafeUTF8(rebasing: components.body )
guard let magnitude: T.Magnitude = NBK.IntegerDescription.decode(digits: digits, solution: solution) else { return nil }
return T(sign: components.sign, magnitude: magnitude)
let digits = NBK.UnsafeUTF8(rebasing: components.body)
guard let magnitude: M = NBK.IntegerDescription.decode(digits: digits, solution: solution) else { return nil }
return SM(sign: components.sign, magnitude: magnitude)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions Sources/Numberick/Documentation.docc/Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,5 @@ Int256(5) % Int(5), UInt256(5) % UInt(5)
- ``LH``
- ``PVO``
- ``QR``
- ``SM``
- ``NBK``
Loading

0 comments on commit 906622f

Please sign in to comment.