Skip to content

Commit 52764c8

Browse files
authored
Merge pull request #19016 from DougGregor/words-collection
[Integer protocols] Make BinaryInteger.Words conform to RandomAccessCollection
2 parents edfcf26 + 0a8058c commit 52764c8

File tree

5 files changed

+23
-63
lines changed

5 files changed

+23
-63
lines changed

stdlib/public/core/IntegerTypes.swift.gyb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,10 +1399,9 @@ ${assignmentOperatorComment(x.operator, True)}
13991399
)._lowWord._value)
14001400
}
14011401

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

stdlib/public/core/Integers.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -630,13 +630,12 @@ public protocol BinaryInteger :
630630
/// - Parameter source: An integer to convert to this type.
631631
init<T : BinaryInteger>(clamping source: T)
632632

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

641640
/// A collection containing the words of this value's binary
642641
/// representation, in order from the least significant to most significant.

test/Prototypes/DoubleWidth.swift.gyb

Lines changed: 12 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ import StdlibUnittest
3838
/// The `DoubleWidth` type is not intended as a replacement for a variable-width
3939
/// integer type. Nesting `DoubleWidth` instances, in particular, may result in
4040
/// undesirable performance.
41-
public struct DoubleWidth<Base : FixedWidthInteger>
42-
where Base.Words : Collection, Base.Magnitude.Words : Collection {
43-
41+
public struct DoubleWidth<Base : FixedWidthInteger> {
4442
public typealias High = Base
4543
public typealias Low = Base.Magnitude
4644

@@ -239,72 +237,33 @@ extension DoubleWidth {
239237
}
240238
}
241239

242-
extension DoubleWidth.Words {
243-
public struct Index {
244-
internal enum _WordsIndexValue: Equatable {
245-
case low(DoubleWidth.Low.Words.Index)
246-
case high(DoubleWidth.High.Words.Index)
247-
}
248-
249-
internal var _value: _WordsIndexValue
250-
251-
internal init(_ _value: _WordsIndexValue) { self._value = _value }
252-
}
253-
}
254-
255-
extension DoubleWidth.Words.Index: Equatable { }
256-
257-
extension DoubleWidth.Words.Index: Comparable {
258-
public static func <(lhs: DoubleWidth.Words.Index, rhs: DoubleWidth.Words.Index) -> Bool {
259-
switch (lhs._value, rhs._value) {
260-
case let (.low(l), .low(r)): return l < r
261-
case (.low, .high): return true
262-
case (.high, .low): return false
263-
case let (.high(l), .high(r)): return l < r
264-
}
265-
}
266-
}
267-
268-
extension DoubleWidth.Words: Collection {
240+
extension DoubleWidth.Words: RandomAccessCollection {
241+
public typealias Index = Int
242+
269243
public var startIndex: Index {
270-
return Index(.low(_low.startIndex))
244+
return 0
271245
}
272246

273247
public var endIndex: Index {
274-
return Index(.high(_high.endIndex))
248+
return count
275249
}
276250

277251
public var count: Int {
278252
if Base.bitWidth < UInt.bitWidth { return 1 }
279-
return Int(_low.count) + Int(_high.count)
280-
}
281-
282-
public func index(after i: Index) -> Index {
283-
switch i._value {
284-
case .low where Base.bitWidth < UInt.bitWidth:
285-
return Index(.high(_high.endIndex))
286-
case let .low(li):
287-
let next = _low.index(after: li)
288-
if next == _low.endIndex {
289-
return Index(.high(_high.startIndex))
290-
} else {
291-
return Index(.low(next))
292-
}
293-
case let .high(hi):
294-
return Index(.high(_high.index(after: hi)))
295-
}
253+
return _low.count + _high.count
296254
}
297255

298256
public subscript(_ i: Index) -> UInt {
299257
if Base.bitWidth < UInt.bitWidth {
300-
precondition(i == Index(.low(_low.startIndex)), "Invalid index")
258+
precondition(i == 0, "Invalid index")
301259
assert(2 * Base.bitWidth <= UInt.bitWidth)
302260
return _low.first! | (_high.first! &<< Base.bitWidth._lowWord)
303261
}
304-
switch i._value {
305-
case let .low(li): return _low[li]
306-
case let .high(hi): return _high[hi]
262+
if i < _low.count {
263+
return _low[i + _low.startIndex]
307264
}
265+
266+
return _high[i - _low.count + _high.startIndex]
308267
}
309268
}
310269

test/api-digester/source-stability.swift.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
/* Generic Signature Changes */
3-
3+
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>
44
/* RawRepresentable Changes */
55

66
/* Removed Decls */

test/stdlib/Integers.swift.gyb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public func _log(_ message: @autoclosure () -> String) {
2929
// print(message())
3030
}
3131

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

728728
expectEqualSequence([1], 1.words)
729729
expectEqualSequence([0], 0.words)
730+
731+
// Random access to words with Int indexing
732+
expectEqual(1, 1.words[0])
730733
}
731734

732735
tests.test("multipliedFullWidth/UInt8") {

0 commit comments

Comments
 (0)