Skip to content

Commit

Permalink
[NBKCoreKit] Simpler integer description decoder.
Browse files Browse the repository at this point in the history
  • Loading branch information
oscbyspro committed Oct 4, 2023
1 parent edd6607 commit afe71ff
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 334 deletions.
1 change: 0 additions & 1 deletion Sources/NBKCoreKit/Private/NBK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
/// - Warning: Do not use this namespace outside of `Numberick` development.
///
public typealias SAM<Magnitude> = NBK.SignAndMagnitude<Magnitude> where Magnitude: NBKUnsignedInteger


/// A namespace for `Numberick` development.
///
Expand Down
126 changes: 23 additions & 103 deletions Sources/NBKCoreKit/Private/NBKIntegerDescription+Decoding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ extension NBK.IntegerDescription {
///
/// - Note: The decoding strategy is case insensitive.
///
@frozen public struct Decoder {
@frozen public struct Decoder<Magnitude: NBKUnsignedInteger> {

public typealias Components = (sign: NBK.Sign, magnitude: Magnitude)

//=--------------------------------------------------------------------=
// MARK: State
Expand All @@ -53,63 +55,21 @@ extension NBK.IntegerDescription {
}

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

@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) })
}

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

@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(_ description: some StringProtocol) -> Components? {
var description = String(description); return description.withUTF8(self.decode)
}

@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)
@inlinable public func decode(_ description: StaticString) -> Components? {
description.withUTF8Buffer(self.decode)
}

//=--------------------------------------------------------------------=
// 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>? {
@inlinable public func decode(_ description: NBK.UnsafeUTF8) -> Components? {
let components = NBK.IntegerDescription.makeSignBody(from: description)
let digits = NBK.UnsafeUTF8(rebasing: components.body)
guard let magnitude: M = NBK.IntegerDescription.decode(digits: digits, solution: self.solution) else { return nil }
guard let magnitude: Magnitude = NBK.IntegerDescription.decode(digits: digits, solution: self.solution) else { return nil }
return SM(sign: components.sign, magnitude: magnitude)
}
}
Expand Down Expand Up @@ -138,74 +98,34 @@ extension NBK.IntegerDescription {
///
/// - Note: The decoding strategy is case insensitive.
///
@frozen public struct DecoderDecodingRadix {
@frozen public struct DecoderDecodingRadix<Magnitude> where Magnitude: NBKUnsignedInteger {

public typealias Components = (sign: NBK.Sign, radix: Int, magnitude: Magnitude)

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

@inlinable public init() { }

//=--------------------------------------------------------------------=
// 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) })
}

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

@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
// MARK: Utilities
//=--------------------------------------------------------------------=

@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(_ description: some StringProtocol) -> Components? {
var description = String(description); return description.withUTF8(self.decode)
}

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

//=--------------------------------------------------------------------=
// 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>? {
@inlinable public func decode(_ description: NBK.UnsafeUTF8) -> Components? {
let components = NBK.IntegerDescription.makeSignRadixBody(from: description)
let solution = AnyRadixSolution<UInt>(components.radix)
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)
let digits = NBK.UnsafeUTF8(rebasing: components.body )
guard let magnitude: Magnitude = NBK.IntegerDescription.decode(digits: digits, solution: solution) else { return nil }
return (sign: components.sign, radix: components.radix, magnitude: magnitude)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extension NBK.SignAndMagnitude {
///
@inlinable public static func compare<Other: NBKUnsignedInteger>(
_ lhs: Components, to rhs: NBK.SignAndMagnitude<Other>.Components, using compare: (Magnitude, Other) -> Int) -> Int {
let absoluteValue: Int
let absoluteValue: Int

if lhs.sign == rhs.sign {
absoluteValue = compare(lhs.magnitude, rhs.magnitude)
Expand Down
13 changes: 7 additions & 6 deletions Sources/NBKDoubleWidthKit/NBKDoubleWidth+Literals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,15 @@ extension NBKDoubleWidth {
///
/// - Note: The decoding strategy is case insensitive.
///
@inlinable public init(stringLiteral source: StaticString) {
if let value = Self(exactlyStringLiteral: source) { self = value } else {
preconditionFailure("\(Self.description) cannot represent \(source)")
@inlinable public init(stringLiteral description: StaticString) {
if let value = Self(exactlyStringLiteral: description) { self = value } else {
preconditionFailure("\(Self.description) cannot represent \(description)")
}
}

@inlinable init?(exactlyStringLiteral source: StaticString) {
let decoder = NBK.IntegerDescription.DecoderDecodingRadix()
if let value: Self = decoder.decode(source) { self = value } else { return nil }
@inlinable init?(exactlyStringLiteral description: StaticString) {
let decoder = NBK.IntegerDescription.DecoderDecodingRadix<Magnitude>()
guard let components = decoder.decode(description) else { return nil }
self.init(sign: components.sign, magnitude: components.magnitude)
}
}
5 changes: 3 additions & 2 deletions Sources/NBKDoubleWidthKit/NBKDoubleWidth+Text.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ extension NBKDoubleWidth {
//=------------------------------------------------------------------------=

@inlinable public init?(_ description: some StringProtocol, radix: Int) {
let decoder = NBK.IntegerDescription.Decoder(radix: radix)
if let value: Self = decoder.decode(description) { self = value } else { return nil }
let decoder = NBK.IntegerDescription.Decoder<Magnitude>(radix: radix)
guard let components = decoder.decode(description) else { return nil }
self.init(sign: components.sign, magnitude: components.magnitude)
}

//=------------------------------------------------------------------------=
Expand Down
Loading

0 comments on commit afe71ff

Please sign in to comment.