Skip to content

[Integer protocols] Make BinaryInteger.Words conform to RandomAccessCollection #19016

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 1 commit into from
Sep 6, 2018
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
3 changes: 1 addition & 2 deletions stdlib/public/core/IntegerTypes.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -1399,10 +1399,9 @@ ${assignmentOperatorComment(x.operator, True)}
)._lowWord._value)
}

// FIXME should be RandomAccessCollection
/// A type that represents the words of this integer.
@_fixed_layout // FIXME(sil-serialize-all)
public struct Words : BidirectionalCollection {
public struct Words : RandomAccessCollection {
public typealias Indices = Range<Int>
public typealias SubSequence = Slice<${Self}.Words>

Expand Down
9 changes: 4 additions & 5 deletions stdlib/public/core/Integers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -630,13 +630,12 @@ public protocol BinaryInteger :
/// - Parameter source: An integer to convert to this type.
init<T : BinaryInteger>(clamping source: T)

// FIXME: Should be `Words : Collection where Words.Element == UInt`
// See <rdar://problem/31798916> for why it isn't.
/// A type that represents the words of a binary integer.
///
/// The `Words` type must conform to the `Collection` protocol with an
/// `Element` type of `UInt`.
associatedtype Words : Sequence where Words.Element == UInt
/// The `Words` type must conform to the `RandomAccessCollection` protocol
/// with an `Element` type of `UInt` and `Index` type of `Int.
associatedtype Words : RandomAccessCollection
where Words.Element == UInt, Words.Index == Int

/// A collection containing the words of this value's binary
/// representation, in order from the least significant to most significant.
Expand Down
65 changes: 12 additions & 53 deletions test/Prototypes/DoubleWidth.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ import StdlibUnittest
/// The `DoubleWidth` type is not intended as a replacement for a variable-width
/// integer type. Nesting `DoubleWidth` instances, in particular, may result in
/// undesirable performance.
public struct DoubleWidth<Base : FixedWidthInteger>
where Base.Words : Collection, Base.Magnitude.Words : Collection {

public struct DoubleWidth<Base : FixedWidthInteger> {
public typealias High = Base
public typealias Low = Base.Magnitude

Expand Down Expand Up @@ -239,72 +237,33 @@ extension DoubleWidth {
}
}

extension DoubleWidth.Words {
public struct Index {
internal enum _WordsIndexValue: Equatable {
case low(DoubleWidth.Low.Words.Index)
case high(DoubleWidth.High.Words.Index)
}

internal var _value: _WordsIndexValue

internal init(_ _value: _WordsIndexValue) { self._value = _value }
}
}

extension DoubleWidth.Words.Index: Equatable { }

extension DoubleWidth.Words.Index: Comparable {
public static func <(lhs: DoubleWidth.Words.Index, rhs: DoubleWidth.Words.Index) -> Bool {
switch (lhs._value, rhs._value) {
case let (.low(l), .low(r)): return l < r
case (.low, .high): return true
case (.high, .low): return false
case let (.high(l), .high(r)): return l < r
}
}
}

extension DoubleWidth.Words: Collection {
extension DoubleWidth.Words: RandomAccessCollection {
public typealias Index = Int

public var startIndex: Index {
return Index(.low(_low.startIndex))
return 0
}

public var endIndex: Index {
return Index(.high(_high.endIndex))
return count
}

public var count: Int {
if Base.bitWidth < UInt.bitWidth { return 1 }
return Int(_low.count) + Int(_high.count)
}

public func index(after i: Index) -> Index {
switch i._value {
case .low where Base.bitWidth < UInt.bitWidth:
return Index(.high(_high.endIndex))
case let .low(li):
let next = _low.index(after: li)
if next == _low.endIndex {
return Index(.high(_high.startIndex))
} else {
return Index(.low(next))
}
case let .high(hi):
return Index(.high(_high.index(after: hi)))
}
return _low.count + _high.count
}

public subscript(_ i: Index) -> UInt {
if Base.bitWidth < UInt.bitWidth {
precondition(i == Index(.low(_low.startIndex)), "Invalid index")
precondition(i == 0, "Invalid index")
assert(2 * Base.bitWidth <= UInt.bitWidth)
return _low.first! | (_high.first! &<< Base.bitWidth._lowWord)
}
switch i._value {
case let .low(li): return _low[li]
case let .high(hi): return _high[hi]
if i < _low.count {
return _low[i + _low.startIndex]
}

return _high[i - _low.count + _high.startIndex]
}
}

Expand Down
2 changes: 1 addition & 1 deletion test/api-digester/source-stability.swift.expected
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

/* Generic Signature Changes */

Protocol BinaryInteger has generic signature change from <Self : CustomStringConvertible, Self : Hashable, Self : Numeric, Self : Strideable, Self.Magnitude : BinaryInteger, Self.Magnitude == Self.Magnitude.Magnitude, Self.Words : Sequence, Self.Words.Element == UInt> to <Self : CustomStringConvertible, Self : Hashable, Self : Numeric, Self : Strideable, Self.Magnitude : BinaryInteger, Self.Magnitude == Self.Magnitude.Magnitude, Self.Words : RandomAccessCollection, Self.Words.Element == UInt, Self.Words.Index == Int>
/* RawRepresentable Changes */

/* Removed Decls */
Expand Down
7 changes: 5 additions & 2 deletions test/stdlib/Integers.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public func _log(_ message: @autoclosure () -> String) {
// print(message())
}

extension FixedWidthInteger where Words : Collection {
extension FixedWidthInteger {
/// a hex representation of every bit in the number
func hexBits(_ bitWidth: Int) -> String {
let hexDigits: [Unicode.Scalar] = [
Expand Down Expand Up @@ -236,7 +236,7 @@ func expectEqual<T : FixedWidthInteger>(
stackTrace: SourceLocStack = SourceLocStack(),
showFrame: Bool = true,
file: String = #file, line: UInt = #line
) where T.Words : Collection {
) {
if expected != actual {
expectationFailure(
"expected: \(String(reflecting: expected))"
Expand Down Expand Up @@ -727,6 +727,9 @@ tests.test("words") {

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

// Random access to words with Int indexing
expectEqual(1, 1.words[0])
}

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