Skip to content

Commit

Permalink
[NBKSignedKit] Words (#81).
Browse files Browse the repository at this point in the history
  • Loading branch information
oscbyspro committed Oct 4, 2023
1 parent 8264de2 commit 954f580
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 5 deletions.
78 changes: 78 additions & 0 deletions Sources/NBKSignedKit/NBKSigned+Words.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,82 @@ extension NBKSigned {
guard let magnitude = Magnitude(words: NBK.MaybeTwosComplement(words, formTwosComplement: isLessThanZero)) else { return nil }
self.init(sign: Sign(isLessThanZero), magnitude: magnitude)
}

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

@inlinable public var words: Words {
Words(self)
}

//*========================================================================*
// MARK: * Words
//*========================================================================*

@frozen public struct Words: RandomAccessCollection {

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

public let count: Int
@usableFromInline let sign: UInt
@usableFromInline let base: NBK.MaybeTwosComplement<Magnitude.Words>

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

@inlinable init(_ source: NBKSigned) {
let isLessThanZero = (source.isLessThanZero)
self.sign = UInt(repeating: isLessThanZero)
self.base = NBK.MaybeTwosComplement(source.magnitude.words, formTwosComplement: isLessThanZero)
self.count = self.base.count + Int(bit:/**/self.base.last?.mostSignificantBit != isLessThanZero)
}

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

@inlinable public var startIndex: Int {
(0 as Int)
}

@inlinable public var endIndex: Int {
self.count
}

@inlinable public var indices: Range<Int> {
0 as Int ..< self.count
}

@inlinable public subscript(index: Int) -> UInt {
index < self.base.endIndex ? self.base[self.base.index(self.base.startIndex, offsetBy: index)] : self.sign
}

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

@inlinable public func distance(from start: Int, to end: Int) -> Int {
end - start
}

@inlinable public func index(after index: Int) -> Int {
index + 1 as Int
}

@inlinable public func index(before index: Int) -> Int {
index - 1 as Int
}

@inlinable public func index(_ index: Int, offsetBy distance: Int) -> Int {
index + distance
}

@inlinable public func index(_ index: Int, offsetBy distance: Int, limitedBy limit: Int) -> Int? {
NBK.arrayIndex(index, offsetBy: distance, limitedBy: limit)
}
}
}
6 changes: 3 additions & 3 deletions Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Words.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ final class NBKFlexibleWidthTestsOnWordsAsUIntXL: XCTestCase {
NBKAssertFromWordsIsSigned(Array([~0/2 + 0]), false, T(words:[~0/2 + 0]))
}

func testWords() {
func testToWords() {
NBKAssertToWords(T(words:[0 ]), [0 ])
NBKAssertToWords(T(words:[1 ]), [1 ])
NBKAssertToWords(T(words:[1, 2 ]), [1, 2 ])
Expand All @@ -62,7 +62,7 @@ final class NBKFlexibleWidthTestsOnWordsAsUIntXL: XCTestCase {
NBKAssertToWords(T(words:[1, 2, 3, 4]), [1, 2, 3, 4])
}

func testWordsX64() throws {
func testToWordsX64() throws {
guard MemoryLayout<UInt>.size == MemoryLayout<UInt64>.size else { throw XCTSkip() }

NBKAssertToWords(T(x64:[0 ] as X), [0 ])
Expand All @@ -78,7 +78,7 @@ final class NBKFlexibleWidthTestsOnWordsAsUIntXL: XCTestCase {
NBKAssertToWords(T(x64:[1, 2, 3, 4] as X), [1, 2, 3, 4])
}

func testWordsX32() throws {
func testToWordsX32() throws {
guard MemoryLayout<UInt>.size == MemoryLayout<UInt32>.size else { throw XCTSkip() }

NBKAssertToWords(T(x32:[0 ] as Y), [0 ])
Expand Down
61 changes: 59 additions & 2 deletions Tests/NBKSignedKitTests/NBKSigned+Words.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@ final class NBKSignedTestsOnWords: XCTestCase {
NBKAssertFromWordsIsSigned(W(repeating: ~0, count: 2), false, nil as T?)
NBKAssertFromWordsIsSigned(W(repeating: ~1, count: 2), false, nil as T?)
}

func testToWords() {
NBKAssertElementsEqual(T(sign: .plus, magnitude: ~0/1 - 0).words, [~0/1 - 0, 0] as W)
NBKAssertElementsEqual(T(sign: .plus, magnitude: ~0/1 - 1).words, [~0/1 - 1, 0] as W)
NBKAssertElementsEqual(T(sign: .minus, magnitude: ~0/1 - 0).words, [ 0/1 + 1, ~0] as W)
NBKAssertElementsEqual(T(sign: .minus, magnitude: ~0/1 - 1).words, [ 0/1 + 2, ~0] as W)

NBKAssertElementsEqual(T(sign: .plus, magnitude: ~0/2 + 2).words, [~0/2 + 2, 0] as W)
NBKAssertElementsEqual(T(sign: .plus, magnitude: ~0/2 + 1).words, [~0/2 + 1, 0] as W)
NBKAssertElementsEqual(T(sign: .plus, magnitude: ~0/2 + 0).words, [~0/2 + 0, ] as W)

NBKAssertElementsEqual(T(sign: .minus, magnitude: ~0/2 + 2).words, [~0/2 + 0, ~0] as W)
NBKAssertElementsEqual(T(sign: .minus, magnitude: ~0/2 + 1).words, [~0/2 + 1, ] as W)
NBKAssertElementsEqual(T(sign: .minus, magnitude: ~0/2 + 0).words, [~0/2 + 2, ] as W)

NBKAssertElementsEqual(T(sign: .plus, magnitude: 0/1 + 0).words, [ 0/1 + 0, ] as W)
NBKAssertElementsEqual(T(sign: .plus, magnitude: 0/1 + 1).words, [ 0/1 + 1, ] as W)
NBKAssertElementsEqual(T(sign: .minus, magnitude: 0/1 + 0).words, [ 0/1 + 0, ] as W)
NBKAssertElementsEqual(T(sign: .minus, magnitude: 0/1 + 1).words, [~0/1 + 0, ] as W)
}
}

//*============================================================================*
Expand All @@ -64,7 +84,7 @@ file: StaticString = #file, line: UInt = #line) {
typealias T = NBKSigned<M>
//=------------------------------------------=
NBKAssertIdentical( T(words: words), integer, file: file, line: line)
//NBKAssertIdentical(integer.flatMap({ T(words: $0.words) }), integer, file: file, line: line)
NBKAssertIdentical(integer.flatMap({ T(words: $0.words) }), integer, file: file, line: line)
}

private func NBKAssertFromWordsIsSigned<M: NBKUnsignedInteger>(
Expand All @@ -78,7 +98,44 @@ file: StaticString = #file, line: UInt = #line) {
}

NBKAssertIdentical( T(words: words, isSigned: isSigned), integer, file: file, line: line)
//NBKAssertIdentical(integer.flatMap({ T(words: $0.words, isSigned: isSigned) }), integer, file: file, line: line)
NBKAssertIdentical(integer.flatMap({ T(words: $0.words, isSigned: isSigned) }), integer, file: file, line: line)
}

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

private func NBKAssertElementsEqual<Base: RandomAccessCollection>(
_ base: Base, _ expectation: [Base.Element],
file: StaticString = #file, line: UInt = #line) where Base.Element: Equatable {
//=------------------------------------------=
XCTAssertEqual(Array(base), expectation, file: file, line: line)
XCTAssertEqual(Array(base.indices.map({ base[$0] })), expectation, file: file, line: line)
//=------------------------------------------=
for distance in 0 ..< base.count {
//=--------------------------------------=
let index0 = base.index(base.startIndex, offsetBy: distance + 0)
let index1 = base.index(base.startIndex, offsetBy: distance + 1)
//=--------------------------------------=
XCTAssertEqual(base[index0],expectation[distance], file: file, line: line)
//=--------------------------------------=
XCTAssertEqual(base.index(before: index1), index0, file: file, line: line)
XCTAssertEqual(base.index(after: index0), index1, file: file, line: line)

XCTAssertEqual(base.index(base.endIndex, offsetBy: distance + 0 - base.count), index0, file: file, line: line)
XCTAssertEqual(base.index(base.endIndex, offsetBy: distance + 1 - base.count), index1, file: file, line: line)
//=--------------------------------------=
XCTAssertEqual(base.distance(from: base.startIndex, to: index0), distance + 0, file: file, line: line)
XCTAssertEqual(base.distance(from: base.startIndex, to: index1), distance + 1, file: file, line: line)

XCTAssertEqual(base.distance(from: index0, to: base.endIndex), base.count - distance - 0, file: file, line: line)
XCTAssertEqual(base.distance(from: index1, to: base.endIndex), base.count - distance - 1, file: file, line: line)
}
//=------------------------------------------=
for distance in 0 ... base.count + 1 {
XCTAssert(base.prefix(distance).elementsEqual(expectation.prefix(distance)), file: file, line: line)
XCTAssert(base.suffix(distance).elementsEqual(expectation.suffix(distance)), file: file, line: line)
}
}

#endif

0 comments on commit 954f580

Please sign in to comment.