Skip to content

Commit

Permalink
[NBKCoreKit] SuccinctInt (#83) (#85).
Browse files Browse the repository at this point in the history
  • Loading branch information
oscbyspro committed Sep 21, 2023
1 parent ce4aba0 commit 42d4863
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 235 deletions.
21 changes: 9 additions & 12 deletions Sources/NBKCoreKit/Private/NBK+Limbs+Comparisons.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,18 @@ extension NBK {

/// A three-way comparison of `lhs` against `rhs`.
@inlinable public static func compareStrictSignedInteger(_ lhs: UnsafeWords, to rhs: UnsafeWords) -> Int {
typealias SBI = SuccinctBinaryInteger<UnsafeWords>
let lhs = SBI.components(fromStrictSignedInteger: lhs)
let rhs = SBI.components(fromStrictSignedInteger: rhs)
return SBI.compare(lhs, to: rhs)
let lhs = SuccinctInt(fromStrictSignedInteger: lhs)!
let rhs = SuccinctInt(fromStrictSignedInteger: rhs)!
return lhs.compared(to: rhs) as Int
}

/// A three-way comparison of `lhs` against `rhs` at `index`.
@inlinable public static func compareStrictSignedInteger(_ lhs: UnsafeWords, to rhs: UnsafeWords, at index: Int) -> Int {
typealias SBI = SuccinctBinaryInteger<UnsafeWords>
let lhs = SBI.components(fromStrictSignedInteger: lhs)
let rhs = SBI.components(fromStrictSignedInteger: rhs)
let lhs = SuccinctInt(fromStrictSignedInteger: lhs)!
let rhs = SuccinctInt(fromStrictSignedInteger: rhs)!
let partition = Swift.min(index, lhs.body.endIndex)
let suffix = UnsafeWords(rebasing: lhs.body.suffix(from: partition))
let comparison = SBI.compare((body: suffix, sign: lhs.sign),to: rhs)
let comparison = SuccinctInt(unchecked: suffix, sign: lhs.sign).compared(to: rhs)
if !comparison.isZero { return comparison }
let prefix = UnsafeWords(rebasing: lhs.body.prefix(upTo: partition))
return Int(bit: partition == index ? !prefix.allSatisfy{ $0.isZero } : lhs.sign)
Expand All @@ -54,10 +52,9 @@ extension NBK {
/// - Note: This operation interprets empty collections as zero.
///
@inlinable public static func compareLenientUnsignedInteger(_ lhs: UnsafeWords, to rhs: UnsafeWords) -> Int {
typealias SBI = SuccinctBinaryInteger<UnsafeWords>
let lhs = SBI.components(fromStrictUnsignedIntegerSubSequence: lhs)
let rhs = SBI.components(fromStrictUnsignedIntegerSubSequence: rhs)
return SBI.compareSameSign(lhs, to: rhs)
let lhs = SuccinctInt(fromStrictUnsignedIntegerSubSequence: lhs)
let rhs = SuccinctInt(fromStrictUnsignedIntegerSubSequence: rhs)
return lhs.compared(toSameSign: rhs) as Int
}

/// A three-way comparison of `lhs` against `rhs` at `index`.
Expand Down

This file was deleted.

41 changes: 0 additions & 41 deletions Sources/NBKCoreKit/Private/NBKSuccinctBinaryInteger.swift

This file was deleted.

64 changes: 64 additions & 0 deletions Sources/NBKCoreKit/Private/NBKSuccinctInt+Comparisons.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//=----------------------------------------------------------------------------=
// This source file is part of the Numberick 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.
//=----------------------------------------------------------------------------=

//*============================================================================*
// MARK: * NBK x Succinct Int x Comparisons
//*============================================================================*

extension NBK.SuccinctInt {

//=------------------------------------------------------------------------=
// MARK: Utilities
//=------------------------------------------------------------------------=

/// A three-way comparison of `self` against `other`.
@inlinable public func compared(to rhs: Self) -> Int {
//=--------------------------------------=
// Plus & Minus
//=--------------------------------------=
if self.sign != rhs.sign {
return self.sign ? -1 : 1
}
//=---------------------------------------=
return self.compared(toSameSign: rhs)
}

/// A three-way comparison of `self` against `other`.
@inlinable public func compared(toSameSign other: Self) -> Int {
//=--------------------------------------=
Swift.assert(self.sign == other.sign)
//=--------------------------------------=
// Long & Short
//=--------------------------------------=
if self.body.count != other.body.count {
return self.sign == (self.body.count > other.body.count) ? -1 : 1
}
//=--------------------------------------=
return self.compared(toSameSizeSameSign: other)
}

/// A three-way comparison of `self` against `other`.
@inlinable public func compared(toSameSizeSameSign other: Self) -> Int {
//=--------------------------------------=
Swift.assert(self.sign/*--*/ == other.sign/*--*/)
Swift.assert(self.body.count == other.body.count)
//=--------------------------------------=
// Word By Word, Back To Front
//=--------------------------------------=
for index in self.body.indices.reversed() {
let lhsWord = self .body[index] as Base.Element
let rhsWord = other.body[index] as Base.Element
if lhsWord != rhsWord { return lhsWord < rhsWord ? -1 : 1 }
}
//=--------------------------------------=
// Same
//=--------------------------------------=
return 0 as Int as Int as Int as Int as Int
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,56 @@
//=----------------------------------------------------------------------------=

//*============================================================================*
// MARK: * NBK x Succinct Binary Integer x Components
// MARK: * NBK x Succinct Int
//*============================================================================*

extension NBK {

/// A succinct binary integer.
///
/// ### Development
///
/// The base needs `zero` to `count` indices for performance reasons.
///
@frozen public struct SuccinctInt<Base> where Base: NBKOffsetAccessCollection,
Base.Element: NBKCoreInteger & NBKUnsignedInteger {

//=--------------------------------------------------------------------=
// MARK: State
//=--------------------------------------------------------------------=

public let body: Base
public let sign: Bool

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

@inlinable public init(_ body: Base, sign: Bool) {
self.body = body
self.sign = sign
precondition(self.body.last != Base.Element(repeating: sign))
}

@inlinable public init(unchecked body: Base, sign: Bool) {
self.body = body
self.sign = sign
Swift.assert(self.body.last != Base.Element(repeating: sign))
}
}
}

//=----------------------------------------------------------------------------=
// MARK: + Pointers
// MARK: + where Base is Unsafe Buffer Pointer
//=----------------------------------------------------------------------------=

extension NBK.SuccinctBinaryInteger {
extension NBK.SuccinctInt {

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

/// Returns the `sign` bit, along with the `body` of significant elements.
/// Creates a new instance from a strict signed integer.
///
/// ```
/// ┌─────────────── → ───────────────┬───────┐
Expand All @@ -39,15 +76,14 @@ extension NBK.SuccinctBinaryInteger {
///
/// `@inline(always)` is required for `NBKFlexibleWidth` performance reasons.
///
@inline(__always) @inlinable public static func components<T>(
fromStrictSignedInteger source: Base) -> Components where Base == UnsafeBufferPointer<T> {
let sign = source.last!.mostSignificantBit
@inline(__always) @inlinable public init?<T>(fromStrictSignedInteger source: Base) where Base == UnsafeBufferPointer<T> {
guard let sign = source.last?.mostSignificantBit else { return nil }
let bits = UInt(repeating: sign)
let body = Base(rebasing: NBK.dropLast(from: source, while:{ $0 == bits }))
return Components(body: body, sign: sign)
let body = Base(rebasing: NBK.dropLast(from: source, while:{ $0 == bits }))
self.init(unchecked: body, sign: sign)
}

/// Returns the `sign` bit, along with the `body` of significant elements.
/// Creates a new instance from a strict unsigned integer subsequence.
///
/// ```
/// ┌─────────────── → ───────────────┬───────┐
Expand All @@ -66,9 +102,7 @@ extension NBK.SuccinctBinaryInteger {
///
/// `@inline(always)` is required for `NBKFlexibleWidth` performance reasons.
///
@inline(__always) @inlinable public static func components<T>(
fromStrictUnsignedIntegerSubSequence source: Base) -> Components where Base == UnsafeBufferPointer<T> {
Components(body: Base(rebasing: NBK.dropLast(from: source, while:{ $0.isZero })), sign: false)
@inline(__always) @inlinable public init<T>(fromStrictUnsignedIntegerSubSequence source: Base) where Base == UnsafeBufferPointer<T> {
self.init(unchecked: Base(rebasing: NBK.dropLast(from: source, while:{ $0.isZero })), sign: false)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,42 @@ private typealias X = [UInt64]
private typealias Y = [UInt32]

//*============================================================================*
// MARK: * NBK x Succinct Binary Integer
// MARK: * NBK x Succinct Int
//*============================================================================*

final class NBKSuccinctBinaryIntegerBenchmarksOnComponents: XCTestCase {
final class NBKSuccinctIntBenchmarks: XCTestCase {

typealias T = NBK.SuccinctBinaryInteger<UnsafeBufferPointer<UInt>>
typealias T = NBK.SuccinctInt<UnsafeBufferPointer<UInt>>

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

func testMakeComponentsFromStrictSignedInteger() {
func testFromStrictSignedInteger() {
var abc = NBK.blackHoleIdentity([ 1, 0, 2, 0, 3, 0, 4, 0] as W)
var xyz = NBK.blackHoleIdentity([~1, ~0, ~2, ~0, ~3, ~0, ~4, ~0] as W)

for _ in 0 ..< 5_000_000 {
abc.withUnsafeBufferPointer { abc in
xyz.withUnsafeBufferPointer { xyz in
NBK.blackHole(T.components(fromStrictSignedInteger: abc))
NBK.blackHole(T.components(fromStrictSignedInteger: xyz))
NBK.blackHole(T(fromStrictSignedInteger: abc)!)
NBK.blackHole(T(fromStrictSignedInteger: xyz)!)
}}

NBK.blackHoleInoutIdentity(&abc)
NBK.blackHoleInoutIdentity(&xyz)
}
}

func testMakeComponentsFromStrictUnsignedIntegerSubSequence() {
func testFromStrictUnsignedIntegerSubSequence() {
var abc = NBK.blackHoleIdentity([ 1, 0, 2, 0, 3, 0, 4, 0] as W)
var xyz = NBK.blackHoleIdentity([~1, ~0, ~2, ~0, ~3, ~0, ~4, ~0] as W)

for _ in 0 ..< 5_000_000 {
abc.withUnsafeBufferPointer { abc in
xyz.withUnsafeBufferPointer { xyz in
NBK.blackHole(T.components(fromStrictUnsignedIntegerSubSequence: abc))
NBK.blackHole(T.components(fromStrictUnsignedIntegerSubSequence: xyz))
NBK.blackHole(T(fromStrictUnsignedIntegerSubSequence: abc))
NBK.blackHole(T(fromStrictUnsignedIntegerSubSequence: xyz))
}}

NBK.blackHoleInoutIdentity(&abc)
Expand Down
Loading

0 comments on commit 42d4863

Please sign in to comment.