Skip to content

Commit

Permalink
[NBKFlexibleWidthKit] Strict bit pattern (#83).
Browse files Browse the repository at this point in the history
  • Loading branch information
oscbyspro committed Sep 18, 2023
1 parent 54546b7 commit 7bbf72c
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 6 deletions.
127 changes: 127 additions & 0 deletions Sources/NBKFlexibleWidthKit/Private/NBKStrictBitPattern+Shifts.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
//=----------------------------------------------------------------------------=
// 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.
//=----------------------------------------------------------------------------=

import NBKCoreKit

//*============================================================================*
// MARK: * NBK x Strict Bit Pattern x Shifts
//*============================================================================*
//=----------------------------------------------------------------------------=
// MARK: + Left
//=----------------------------------------------------------------------------=

extension NBKStrictBitPattern where Base: MutableCollection, Base.Indices == Range<Int> {

//=------------------------------------------------------------------------=
// MARK: Transformations
//=------------------------------------------------------------------------=

/// Performs a left shift, assuming the `base` is ordered from least to most significant.
///
/// - Parameters:
/// - pointee: The mutable collection.
/// - environment: The bit used to fill the void.
/// - major: `0 <= major < base.count`
/// - minor: `1 <= minor < Base.Element.bitWidth`
///
@inlinable public mutating func bitshiftLeft(environment: Bool, major: Int, minorAtLeastOne minor: Int) {
precondition(0 <= major && major < self.base.count/*--*/, NBK.callsiteOutOfBoundsInfo())
precondition(0 < minor && minor < Base.Element.bitWidth, NBK.callsiteOutOfBoundsInfo())
//=--------------------------------------=
let push = NBK.initOrBitCast(truncating: minor, as: Base.Element.self)
let pull = NBK.initOrBitCast(truncating: Base.Element.bitWidth - minor, as: Base.Element.self)
let fill = Base.Element(repeating: environment)
//=--------------------------------------=
var destination = self.base.endIndex as Int
let offset: Int = ~(major)
var element = self.base[destination &+ offset]
//=--------------------------------------=
while destination > self.base.startIndex {
self.base.formIndex(before: &destination)
let pushed = element &<< push
element = destination > major ? self.base[destination &+ offset] : fill
let pulled = element &>> pull
self.base[destination] = pushed | pulled
}
}

/// Performs a left shift, assuming the `base` is ordered from least to most significant.
///
/// - Parameters:
/// - environment: The bit used to fill the void.
/// - major: `1 <= major < base.count`
///
@inlinable public mutating func bitshiftLeft(environment: Bool, majorAtLeastOne major: Int) {
precondition(0 < major && major < self.base.count, NBK.callsiteOutOfBoundsInfo())
//=--------------------------------------=
let fill = Base.Element(repeating: environment)
//=--------------------------------------=
for destination in self.base.indices.reversed() {
self.base[destination] = destination >= major ? self.base[destination - major] : fill
}
}
}

//=----------------------------------------------------------------------------=
// MARK: + Right
//=----------------------------------------------------------------------------=

extension NBKStrictBitPattern where Base: MutableCollection {

//=------------------------------------------------------------------------=
// MARK: Transformations
//=------------------------------------------------------------------------=

/// Performs a right shift, assuming the `base` is ordered from least to most significant.
///
/// - Parameters:
/// - environment: The bit used to fill the void.
/// - major: `0 <= major < base.count`
/// - minor: `1 <= minor < Base.Element.bitWidth`
///
@inlinable public mutating func bitshiftRight(environment: Bool, major: Int, minorAtLeastOne minor: Int) {
precondition(0 <= major && major < self.base.count/*--*/, NBK.callsiteOutOfBoundsInfo())
precondition(0 < minor && minor < Base.Element.bitWidth, NBK.callsiteOutOfBoundsInfo())
//=--------------------------------------=
let push = NBK.initOrBitCast(truncating: minor, as: Base.Element.self)
let pull = NBK.initOrBitCast(truncating: Base.Element.bitWidth - minor, as: Base.Element.self)
let fill = Base.Element(repeating: environment)
//=--------------------------------------=
var destination = self.base.startIndex
let edge = self.base.distance(from: major, to: self.base.endIndex)
var element = self.base[major] as Base.Element
//=--------------------------------------=
while destination < self.base.endIndex {
let after = self.base.index(after: destination)
let pushed = element &>> push
element = after < edge ? self.base[after &+ major] : fill
let pulled = element &<< pull
self.base[destination] = pushed | pulled
destination = after
}
}

/// Performs a right shift, assuming the `base` is ordered from least to most significant.
///
/// - Parameters:
/// - environment: The bit used to fill the void.
/// - major: `1 <= major < base.count`
///
@inlinable public mutating func bitshiftRight(environment: Bool, majorAtLeastOne major: Int) {
precondition(0 < major && major < self.base.count, NBK.callsiteOutOfBoundsInfo())
//=--------------------------------------=--=
let fill = Base.Element(repeating: environment)
//=--------------------------------------=
let edge = self.base.distance(from: major, to: self.base.endIndex)
//=--------------------------------------=
for destination in self.base.indices {
self.base[destination] = destination < edge ? self.base[destination + major] : fill
}
}
}
93 changes: 93 additions & 0 deletions Sources/NBKFlexibleWidthKit/Private/NBKStrictBitPattern.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//=----------------------------------------------------------------------------=
// 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.
//=----------------------------------------------------------------------------=

import NBKCoreKit

//*============================================================================*
// MARK: * NBK x Strict Bit Pattern
//*============================================================================*
//=----------------------------------------------------------------------------=
// TODO: * NBKOffsetIndexed protocol with static index requirements (perf.)
//=----------------------------------------------------------------------------=

@frozen public struct NBKStrictBitPattern<Base: RandomAccessCollection> where
Base.Element: NBKCoreInteger & NBKUnsignedInteger, Base.Indices == Range<Int> {

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

@usableFromInline var base: Base

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

@inlinable public init(_ base: Base) {
self.base = base
precondition(Self.validate(self.base))
}

@inlinable public init(unchecked base: Base) {
self.base = base
Swift.assert(Self.validate(self.base))
}

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

@inlinable public static func validate(_ base: Base) -> Bool {
!base.isEmpty && base.startIndex.isZero // TODO: req. NBKOffsetIndexed
}
}

//=----------------------------------------------------------------------------=
// MARK: + Collection
//=----------------------------------------------------------------------------=

extension NBKStrictBitPattern {

//=------------------------------------------------------------------------=
// MARK: Accessors
//=------------------------------------------------------------------------=

@inlinable public var first: Base.Element {
self.base[self.base.startIndex]
}

@inlinable public var last: Base.Element {
self.base[self.lastIndex]
}

@inlinable public var lastIndex: Base.Index {
self.base.index(before: self.base.endIndex)
}
}

//=----------------------------------------------------------------------------=
// MARK: + Collection x Mutable
//=----------------------------------------------------------------------------=

extension NBKStrictBitPattern where Base: MutableCollection {

//=------------------------------------------------------------------------=
// MARK: Accessors
//=------------------------------------------------------------------------=

@inlinable public var first: Base.Element {
get { self.base[self.base.startIndex] }
set { self.base[self.base.startIndex] = newValue }
}

@inlinable public var last: Base.Element {
get { self.base[self.lastIndex] }
set { self.base[self.lastIndex] = newValue }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import NBKCoreKit
//*============================================================================*
// MARK: * NBK x Strict Unsigned Integer x Addition
//*============================================================================*
//=----------------------------------------------------------------------------=
// MARK: + Bit
//=----------------------------------------------------------------------------=

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import NBKCoreKit
//*============================================================================*
// MARK: * NBK x Strict Unsigned Integer x Division
//*============================================================================*
//=----------------------------------------------------------------------------=
// MARK: + Digit
//=----------------------------------------------------------------------------=

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import NBKCoreKit
//*============================================================================*
// MARK: * NBK x Strict Unsigned Integer x Multiplication
//*============================================================================*
//=----------------------------------------------------------------------------=
// MARK: + Digit
//=----------------------------------------------------------------------------=

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import NBKCoreKit
//*============================================================================*
// MARK: * NBK x Strict Unsigned Integer x Shifts
//*============================================================================*
//=----------------------------------------------------------------------------=
// MARK: + Left
//=----------------------------------------------------------------------------=

Expand Down Expand Up @@ -70,8 +71,8 @@ extension NBKStrictUnsignedInteger where Base: MutableCollection, Base.Indices =
/// - major: `0 <= major < base.endIndex`
/// - minor: `1 <= minor < Base.Element.bitWidth`
///
@inlinable public mutating func bitshiftLeft(major: Int, minorAtLeastOne bits: Int) {
NBK.bitshiftLeftAsFixedLimbsCodeBlock(&self.base, environment: false, limbs: major, atLeastOneBit: bits)
@inlinable public mutating func bitshiftLeft(major: Int, minorAtLeastOne minor: Int) {
self.bitPattern.bitshiftLeft(environment: false, major: major, minorAtLeastOne: minor)
}

/// Performs a left shift.
Expand All @@ -80,7 +81,7 @@ extension NBKStrictUnsignedInteger where Base: MutableCollection, Base.Indices =
/// - major: `1 <= major < base.endIndex`
///
@inlinable public mutating func bitshiftLeft(majorAtLeastOne major: Int) {
NBK.bitshiftLeftAsFixedLimbsCodeBlock(&self.base, environment: false, atLeastOneLimb: major)
self.bitPattern.bitshiftLeft(environment: false, majorAtLeastOne: major)
}
}

Expand Down Expand Up @@ -143,8 +144,8 @@ extension NBKStrictUnsignedInteger where Base: MutableCollection, Base.Indices =
/// - major: `0 <= major < base.endIndex`
/// - minor: `1 <= minor < Base.Element.bitWidth`
///
@inlinable public mutating func bitshiftRight(major: Int, minorAtLeastOne bits: Int) {
NBK.bitshiftRightAsFixedLimbsCodeBlock(&self.base, environment: false, limbs: major, atLeastOneBit: bits)
@inlinable public mutating func bitshiftRight(major: Int, minorAtLeastOne minor: Int) {
self.bitPattern.bitshiftRight(environment: false, major: major, minorAtLeastOne: minor)
}

/// Performs an unsigned right shift.
Expand All @@ -153,6 +154,6 @@ extension NBKStrictUnsignedInteger where Base: MutableCollection, Base.Indices =
/// - major: `1 <= major < base.endIndex`
///
@inlinable public mutating func bitshiftRight(majorAtLeastOne major: Int) {
NBK.bitshiftRightAsFixedLimbsCodeBlock(&self.base, environment: false, atLeastOneLimb: major)
self.bitPattern.bitshiftRight(environment: false, majorAtLeastOne: major)
}
}
21 changes: 21 additions & 0 deletions Sources/NBKFlexibleWidthKit/Private/NBKStrictUnsignedInteger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,24 @@ extension NBKStrictUnsignedInteger where Base: MutableCollection {
set { self.base[self.lastIndex] = newValue }
}
}

//=----------------------------------------------------------------------------=
// MARK: + Views x Bit Pattern
//=----------------------------------------------------------------------------=

extension NBKStrictUnsignedInteger where Base.Indices == Range<Int> {

//=------------------------------------------------------------------------=
// MARK: Utilities x Views
//=------------------------------------------------------------------------=

@inlinable public var bitPattern: NBKStrictBitPattern<Base> {
_read {
yield NBKStrictBitPattern(unchecked: self.base)
}

_modify {
var view = self.bitPattern; yield &view; self = Self(unchecked: view.base)
}
}
}

0 comments on commit 7bbf72c

Please sign in to comment.