Skip to content

[stdlib] BinaryInteger func word(at:) => var words: Words #8984

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions stdlib/public/core/Integers.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -1464,7 +1464,7 @@ public protocol BinaryInteger :
/// Returns the n-th word, counting from the least significant to most
/// significant, of this value's binary representation.
///
/// The `word(at:)` method returns negative values in two's complement
/// The `_word(at:)` method returns negative values in two's complement
/// representation, regardless of a type's underlying implementation. If `n`
/// is greater than the number of words in this value's current
/// representation, the result is `0` for positive numbers and `~0` for
Expand All @@ -1474,7 +1474,13 @@ public protocol BinaryInteger :
/// most significant. `n` must be greater than or equal to zero.
/// - Returns: An word-sized, unsigned integer with the bit pattern of the
/// n-th word of this value.
func word(at n: Int) -> UInt
func _word(at n: Int) -> UInt

// FIXME(integers): add doc comments
// FIXME: Should be `Words : Collection where Words.Iterator.Element == UInt`
// See <rdar://problem/31798916> for why it isn't.
associatedtype Words
var words: Words { get }

/// The number of bits in the current binary representation of this value.
///
Expand Down Expand Up @@ -1918,6 +1924,18 @@ extension BinaryInteger {
}
#endif

extension BinaryInteger {
// FIXME(integers): inefficient. Should get rid of _word(at:) and
// countRepresentedWords, and make `words` the basic operation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about CollectionOfOne<UInt>. But _UIntBuffer<UInt, UInt64> looks like a better solution for 32-bit platforms. Thanks!

public var words: [UInt] {
var result = [UInt]()
result.reserveCapacity(countRepresentedWords)
for i in 0..<self.countRepresentedWords {
result.append(_word(at: i))
}
return result
}
}

//===----------------------------------------------------------------------===//
//===--- FixedWidthInteger ------------------------------------------------===//
Expand Down Expand Up @@ -2306,7 +2324,7 @@ ${unsafeOperationComment(x.operator)}
@inline(__always)
public init<T : BinaryInteger>(extendingOrTruncating source: T) {
if Self.bitWidth <= ${word_bits} {
self = Self.init(_truncatingBits: source.word(at: 0))
self = Self.init(_truncatingBits: source._word(at: 0))
}
else {
var result: Self = source < (0 as T) ? ~0 : 0
Expand All @@ -2317,7 +2335,7 @@ ${unsafeOperationComment(x.operator)}
// that Self.bitWidth > ${word_bits}. Not masking results in
// infinite recursion.
result &<<= (${word_bits} as Self)
result |= Self(_truncatingBits: source.word(at: n))
result |= Self(_truncatingBits: source._word(at: n))
n -= 1
}

Expand Down Expand Up @@ -2865,7 +2883,7 @@ ${operatorComment(x.operator, True)}
}

@_transparent
public func word(at n: Int) -> UInt {
public func _word(at n: Int) -> UInt {
_precondition(n >= 0, "Negative word index")
if _fastPath(n < countRepresentedWords) {
let shift = UInt(n._value) &* ${word_bits}
Expand Down Expand Up @@ -3302,15 +3320,15 @@ public struct DoubleWidth<T : FixedWidthInteger>
fatalError()
}

public func word(at n: Int) -> UInt {
public func _word(at n: Int) -> UInt {
if T.bitWidth < ${word_bits} || T.bitWidth % ${word_bits} != 0 {
fatalError("word(at:) is not supported on this type")
fatalError("_word(at:) is not supported on this type")
}
// TODO: move to Int128 just like init(_builtinIntegerLiteral:) ?
let wordsInT = T.bitWidth / ${word_bits}
return (n < wordsInT) ?
_storage.low.word(at: n) :
_storage.high.word(at: n - wordsInT)
_storage.low._word(at: n) :
_storage.high._word(at: n - wordsInT)
}

public static var isSigned: Bool {
Expand Down
6 changes: 3 additions & 3 deletions test/Prototypes/BigInt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public struct _BigInt<Word: FixedWidthInteger & UnsignedInteger> :
let wordRatio = UInt.bitWidth / Word.bitWidth
_sanityCheck(wordRatio != 0)
for i in 0..<source.countRepresentedWords {
var sourceWord = source.word(at: i)
var sourceWord = source._word(at: i)
for _ in 0..<wordRatio {
_data.append(Word(extendingOrTruncating: sourceWord))
sourceWord >>= Word.bitWidth
Expand Down Expand Up @@ -660,7 +660,7 @@ public struct _BigInt<Word: FixedWidthInteger & UnsignedInteger> :
}
}

public func word(at n: Int) -> UInt {
public func _word(at n: Int) -> UInt {
let ratio = UInt.bitWidth / Word.bitWidth
_sanityCheck(ratio != 0)

Expand Down Expand Up @@ -1293,7 +1293,7 @@ struct Bit : FixedWidthInteger, UnsignedInteger {
return self
}

func word(at n: Int) -> UInt {
func _word(at n: Int) -> UInt {
return UInt(value)
}

Expand Down
31 changes: 21 additions & 10 deletions test/stdlib/Integers.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ extension FixedWidthInteger {
@discardableResult
// @_transparent
public mutating func replaceUWord(_ n: Int, with newBits: UInt) -> Bool {
let flippedBits = word(at: n) ^ newBits
let flippedBits = _word(at: n) ^ newBits
self ^= Self(_truncatingBits: flippedBits) << (${word_bits} * n)
if word(at: n) != newBits {
if _word(at: n) != newBits {
_log("###### overflow replacing word \(n) with \(newBits.hex)")
}
return word(at: n) == newBits
return _word(at: n) == newBits
}

/// a hex representation of every bit in the number
Expand All @@ -54,7 +54,7 @@ extension FixedWidthInteger {
if nibbles % 4 == 0 && nibbles != 0 {
result.insert("_", at: result.startIndex)
}
let lowUWord = x.word(at: 0)
let lowUWord = x._word(at: 0)
result.insert(
hexDigits[Int(lowUWord._value) & 0xF],
at: result.startIndex
Expand Down Expand Up @@ -495,16 +495,27 @@ tests.test("Basics") {

tests.test("word") {
let x = UDWord(Int.max)
expectEqual(Int.max._lowUWord, x.word(at: 0))
expectEqual(0, x.word(at: 1))
expectEqual(Int.max._lowUWord, x._word(at: 0))
expectEqual(0, x._word(at: 1))

let y = DWord(Int.min)
expectEqual(Int.min._lowUWord, y.word(at: 0))
expectEqual(~0, y.word(at: 1))
expectEqual(Int.min._lowUWord, y._word(at: 0))
expectEqual(~0, y._word(at: 1))

let z = UInt(~Int.min) + 1
expectEqual(Int.min._lowUWord, z.word(at: 0))
expectEqual(0, z.word(at: 1))
expectEqual(Int.min._lowUWord, z._word(at: 0))
expectEqual(0, z._word(at: 1))
}

tests.test("words") {
expectEqualSequence([UInt.max], (-1 as Int).words)
expectEqualSequence([UInt.max], (-1 as Int8).words)
expectEqualSequence([UInt.max], (-1 as Int16).words)
expectEqualSequence([UInt.max], (-1 as Int32).words)
expectEqualSequence([UInt.max], (-1 as Int64).words)

expectEqualSequence([1], 1.words)
expectEqualSequence([0], 0.words)
}

tests.test("multipliedFullWidth/UInt8") {
Expand Down