Skip to content

Commit c4c0779

Browse files
committed
[SE-0368] StaticBigInt: use non-generic subscript
1 parent e570c03 commit c4c0779

File tree

2 files changed

+55
-166
lines changed

2 files changed

+55
-166
lines changed

stdlib/public/core/StaticBigInt.swift

Lines changed: 21 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ extension StaticBigInt {
6565
/// including the sign bit, and excluding the sign extension.
6666
///
6767
/// The following examples show the least significant byte of each value's
68-
/// binary representation, separated into excluded and included bits.
68+
/// binary representation, separated into excluded and included bits. Negative
69+
/// values are in two's complement.
6970
///
7071
/// * `-4` (`0b11111_100`) is 3 bits.
7172
/// * `-3` (`0b11111_101`) is 3 bits.
@@ -81,84 +82,32 @@ extension StaticBigInt {
8182
Int(Builtin.bitWidth_IntLiteral(_value))
8283
}
8384

84-
/// Returns an element of this value's binary representation.
85+
/// Returns a 32-bit or 64-bit word of this value's binary representation.
8586
///
86-
/// The elements are ordered from least significant to most significant, with
87-
/// an infinite sign extension. Negative values are in two's complement.
87+
/// The words are ordered from least significant to most significant, with an
88+
/// infinite sign extension. Negative values are in two's complement.
8889
///
89-
/// let value: StaticBigInt = -0x8000000000000000_0000000000000000
90-
/// value.bitWidth //-> 128
91-
/// value[0] as UInt64 //-> 0x0000000000000000
92-
/// value[1] as UInt64 //-> 0x8000000000000000
93-
/// value[2] as UInt64 //-> 0xFFFFFFFFFFFFFFFF
90+
/// let negative: StaticBigInt = -0x0123456789ABCDEF
91+
/// negative.signum() //-> -1
92+
/// negative.bitWidth //-> 58
93+
/// negative[0] //-> 0xFEDCBA9876543211
94+
/// negative[1] //-> 0xFFFFFFFFFFFFFFFF
9495
///
95-
/// let value: StaticBigInt = -1
96-
/// value.bitWidth //-> 1
97-
/// value[0] as UInt64 //-> 0xFFFFFFFFFFFFFFFF
98-
/// value[1] as UInt64 //-> 0xFFFFFFFFFFFFFFFF
99-
/// value[2] as UInt64 //-> 0xFFFFFFFFFFFFFFFF
100-
///
101-
/// let value: StaticBigInt = +0
102-
/// value.bitWidth //-> 1
103-
/// value[0] as UInt64 //-> 0x0000000000000000
104-
/// value[1] as UInt64 //-> 0x0000000000000000
105-
/// value[2] as UInt64 //-> 0x0000000000000000
106-
///
107-
/// let value: StaticBigInt = +0x7FFFFFFFFFFFFFFF_FFFFFFFFFFFFFFFF
108-
/// value.bitWidth //-> 128
109-
/// value[0] as UInt64 //-> 0xFFFFFFFFFFFFFFFF
110-
/// value[1] as UInt64 //-> 0x7FFFFFFFFFFFFFFF
111-
/// value[2] as UInt64 //-> 0x0000000000000000
96+
/// let positive: StaticBigInt = +0x0123456789ABCDEF
97+
/// positive.signum() //-> +1
98+
/// positive.bitWidth //-> 58
99+
/// positive[0] //-> 0x0123456789ABCDEF
100+
/// positive[1] //-> 0x0000000000000000
112101
///
113102
/// - Parameter index: A nonnegative zero-based index.
114-
/// - Returns: A fixed-width unsigned integer. Word-sized types are preferred.
115103
@available(SwiftStdlib 5.8, *)
116104
@inlinable
117-
public subscript<Element>(_ index: Int) -> Element
118-
where
119-
Element: _ExpressibleByBuiltinIntegerLiteral,
120-
Element: FixedWidthInteger,
121-
Element: UnsignedInteger
122-
{
105+
public subscript(_ index: Int) -> UInt {
123106
_precondition(index >= 0, "index out of range")
124-
guard index * Element.bitWidth < bitWidth else {
107+
guard (index * UInt.bitWidth) < bitWidth else {
125108
return _isNegative ? ~0 : 0
126109
}
127-
guard Element.bitWidth == UInt.bitWidth else {
128-
return self[_slowElementAt: index]
129-
}
130-
return Element(_truncatingBits: UInt(
131-
Builtin.wordAtIndex_IntLiteral(_value, index._builtinWordValue)
132-
))
133-
}
134-
135-
@available(SwiftStdlib 5.8, *)
136-
@usableFromInline
137-
internal subscript<Element>(_slowElementAt index: Int) -> Element
138-
where
139-
Element: _ExpressibleByBuiltinIntegerLiteral,
140-
Element: FixedWidthInteger,
141-
Element: UnsignedInteger
142-
{
143-
_internalInvariant(index >= 0, "index out of range")
144-
let bitIndex = index * Element.bitWidth
145-
var wordIndex = bitIndex >> UInt.bitWidth.trailingZeroBitCount
146-
if UInt.bitWidth.isMultiple(of: Element.bitWidth) {
147-
// Create a single-word element, using a *masking* shift.
148-
let word: UInt = self[wordIndex]
149-
return Element(_truncatingBits: word &>> bitIndex)
150-
} else if Element.bitWidth.isMultiple(of: UInt.bitWidth) {
151-
// Create a multi-word element.
152-
var result = Element.zero
153-
for wordOffset in 0..<(Element.bitWidth / UInt.bitWidth) {
154-
let word: UInt = self[wordIndex]
155-
result |= Element(_truncatingBits: word) << (wordOffset * UInt.bitWidth)
156-
wordIndex += 1
157-
}
158-
return result
159-
} else {
160-
_preconditionFailure("element type not supported")
161-
}
110+
return UInt(Builtin.wordAtIndex_IntLiteral(_value, index._builtinWordValue))
162111
}
163112
}
164113

@@ -187,12 +136,13 @@ extension StaticBigInt: CustomDebugStringConvertible {
187136
typealias Element = UInt32
188137
let hexDigitsPerElement = Element.bitWidth / 4
189138
_internalInvariant(hexDigitsPerElement <= _SmallString.capacity)
139+
_internalInvariant(UInt.bitWidth.isMultiple(of: Element.bitWidth))
190140

191141
// Lazily compute the magnitude, starting with the least significant bits.
192142
var overflow = isNegative
193143
for bitIndex in stride(from: 0, to: bitWidth, by: Element.bitWidth) {
194-
let elementIndex = bitIndex >> Element.bitWidth.trailingZeroBitCount
195-
var element: Element = self[elementIndex]
144+
let wordIndex = bitIndex >> UInt.bitWidth.trailingZeroBitCount
145+
var element = Element(_truncatingBits: self[wordIndex] &>> bitIndex)
196146
if isNegative {
197147
element = ~element
198148
if overflow {

test/stdlib/StaticBigInt.swift

Lines changed: 34 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//
1313
// RUN: %target-run-simple-swift(-parse-as-library)
1414
// REQUIRES: executable_test
15+
// REQUIRES: PTRSIZE=64
1516
// REQUIRES: reflection
1617
// END.
1718
//
@@ -35,9 +36,7 @@ final class StaticBigIntTests: Base {
3536
let testCase = StaticBigIntTests()
3637
let testSuite = TestSuite("StaticBigIntTests")
3738
testSuite.test("AssociatedType", testCase.testAssociatedType)
38-
testSuite.test("SignumAndBitWidth", testCase.testSignumAndBitWidth)
39-
testSuite.test("SubscriptAsUInt32", testCase.testSubscriptAsUInt32)
40-
testSuite.test("SubscriptAsUInt64", testCase.testSubscriptAsUInt64)
39+
testSuite.test("BinaryRepresentation", testCase.testBinaryRepresentation)
4140
testSuite.test("TextualRepresentation", testCase.testTextualRepresentation)
4241
runAllTests()
4342
#endif
@@ -78,24 +77,18 @@ extension StaticBigIntTests {
7877
@available(SwiftStdlib 5.8, *)
7978
func testAssociatedType() {
8079
do {
81-
let wrapper: Wrapper = -0x0123_4567_89AB_CDEF
82-
expectEqual( -1, wrapper.actual.signum())
83-
expectEqual( 58, wrapper.actual.bitWidth)
84-
expectEqual(0x3211, wrapper.actual[0] as UInt16)
85-
expectEqual(0x7654, wrapper.actual[1] as UInt16)
86-
expectEqual(0xBA98, wrapper.actual[2] as UInt16)
87-
expectEqual(0xFEDC, wrapper.actual[3] as UInt16)
88-
expectEqual(0xFFFF, wrapper.actual[4] as UInt16)
80+
let negative = Wrapper(-0x0123456789ABCDEF)
81+
expectEqual(-1, negative.actual.signum())
82+
expectEqual(58, negative.actual.bitWidth)
83+
expectEqual(0xFEDCBA9876543211, negative.actual[0])
84+
expectEqual(0xFFFFFFFFFFFFFFFF, negative.actual[1])
8985
}
9086
do {
91-
let wrapper: Wrapper = 0x0123_4567_89AB_CDEF
92-
expectEqual( +1, wrapper.actual.signum())
93-
expectEqual( 58, wrapper.actual.bitWidth)
94-
expectEqual(0xCDEF, wrapper.actual[0] as UInt16)
95-
expectEqual(0x89AB, wrapper.actual[1] as UInt16)
96-
expectEqual(0x4567, wrapper.actual[2] as UInt16)
97-
expectEqual(0x0123, wrapper.actual[3] as UInt16)
98-
expectEqual(0x0000, wrapper.actual[4] as UInt16)
87+
let positive = Wrapper(0x0123456789ABCDEF)
88+
expectEqual(+1, positive.actual.signum())
89+
expectEqual(58, positive.actual.bitWidth)
90+
expectEqual(0x0123456789ABCDEF, positive.actual[0])
91+
expectEqual(0x0000000000000000, positive.actual[1])
9992
}
10093
}
10194
}
@@ -108,87 +101,33 @@ extension StaticBigIntTests {
108101
extension StaticBigIntTests {
109102

110103
@available(SwiftStdlib 5.8, *)
111-
func testSignumAndBitWidth() {
112-
typealias Expected = (signum: Int, bitWidth: Int)
104+
func testBinaryRepresentation() {
105+
typealias Expected = (signum: Int, bitWidth: Int, words: [UInt])
106+
let m = UInt(bitPattern: .min)
113107
let keyValuePairs: KeyValuePairs<StaticBigInt, Expected> = [
114-
-0x80000000000000000000000000000002: (signum: -1, bitWidth: 129),
115-
-0x80000000000000000000000000000001: (signum: -1, bitWidth: 129),
116-
-0x80000000000000000000000000000000: (signum: -1, bitWidth: 128),
117-
-0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF: (signum: -1, bitWidth: 128),
118-
-0x4: (signum: -1, bitWidth: 3),
119-
-0x3: (signum: -1, bitWidth: 3),
120-
-0x2: (signum: -1, bitWidth: 2),
121-
-0x1: (signum: -1, bitWidth: 1),
122-
+0x0: (signum: 0, bitWidth: 1),
123-
+0x1: (signum: +1, bitWidth: 2),
124-
+0x2: (signum: +1, bitWidth: 3),
125-
+0x3: (signum: +1, bitWidth: 3),
126-
+0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE: (signum: +1, bitWidth: 128),
127-
+0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF: (signum: +1, bitWidth: 128),
128-
+0x80000000000000000000000000000000: (signum: +1, bitWidth: 129),
129-
+0x80000000000000000000000000000001: (signum: +1, bitWidth: 129),
108+
-0x80000000000000000000000000000002: (-1, 129, [~1, ~m, ~0]),
109+
-0x80000000000000000000000000000001: (-1, 129, [~0, ~m, ~0]),
110+
-0x80000000000000000000000000000000: (-1, 128, [ 0, m, ~0]),
111+
-0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF: (-1, 128, [ 1, m, ~0]),
112+
-0x4: (-1, 3, [~3, ~0, ~0]),
113+
-0x3: (-1, 3, [~2, ~0, ~0]),
114+
-0x2: (-1, 2, [~1, ~0, ~0]),
115+
-0x1: (-1, 1, [~0, ~0, ~0]),
116+
+0x0: ( 0, 1, [ 0, 0, 0]),
117+
+0x1: (+1, 2, [ 1, 0, 0]),
118+
+0x2: (+1, 3, [ 2, 0, 0]),
119+
+0x3: (+1, 3, [ 3, 0, 0]),
120+
+0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE: (+1, 128, [~1, ~m, 0]),
121+
+0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF: (+1, 128, [~0, ~m, 0]),
122+
+0x80000000000000000000000000000000: (+1, 129, [ 0, m, 0]),
123+
+0x80000000000000000000000000000001: (+1, 129, [ 1, m, 0]),
130124
]
131125
for (actual, expected) in keyValuePairs {
132126
expectEqual(expected.signum, actual.signum())
133127
expectEqual(expected.bitWidth, actual.bitWidth)
134-
}
135-
}
136-
137-
@available(SwiftStdlib 5.8, *)
138-
func testSubscriptAsUInt32() {
139-
let m = UInt32(bitPattern: .min)
140-
let keyValuePairs: KeyValuePairs<StaticBigInt, [UInt32]> = [
141-
-0x80000000000000000000000000000002: [~1, ~0, ~0, ~m, ~0],
142-
-0x80000000000000000000000000000001: [~0, ~0, ~0, ~m, ~0],
143-
-0x80000000000000000000000000000000: [ 0, 0, 0, m, ~0],
144-
-0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF: [ 1, 0, 0, m, ~0],
145-
-0x4: [~3, ~0, ~0, ~0, ~0],
146-
-0x3: [~2, ~0, ~0, ~0, ~0],
147-
-0x2: [~1, ~0, ~0, ~0, ~0],
148-
-0x1: [~0, ~0, ~0, ~0, ~0],
149-
+0x0: [ 0, 0, 0, 0, 0],
150-
+0x1: [ 1, 0, 0, 0, 0],
151-
+0x2: [ 2, 0, 0, 0, 0],
152-
+0x3: [ 3, 0, 0, 0, 0],
153-
+0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE: [~1, ~0, ~0, ~m, 0],
154-
+0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF: [~0, ~0, ~0, ~m, 0],
155-
+0x80000000000000000000000000000000: [ 0, 0, 0, m, 0],
156-
+0x80000000000000000000000000000001: [ 1, 0, 0, m, 0],
157-
]
158-
for (actual, expected) in keyValuePairs {
159-
expectEqual(expected[0], actual[0])
160-
expectEqual(expected[1], actual[1])
161-
expectEqual(expected[2], actual[2])
162-
expectEqual(expected[3], actual[3])
163-
expectEqual(expected[4], actual[4])
164-
}
165-
}
166-
167-
@available(SwiftStdlib 5.8, *)
168-
func testSubscriptAsUInt64() {
169-
let m = UInt64(bitPattern: .min)
170-
let keyValuePairs: KeyValuePairs<StaticBigInt, [UInt64]> = [
171-
-0x80000000000000000000000000000002: [~1, ~m, ~0],
172-
-0x80000000000000000000000000000001: [~0, ~m, ~0],
173-
-0x80000000000000000000000000000000: [ 0, m, ~0],
174-
-0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF: [ 1, m, ~0],
175-
-0x4: [~3, ~0, ~0],
176-
-0x3: [~2, ~0, ~0],
177-
-0x2: [~1, ~0, ~0],
178-
-0x1: [~0, ~0, ~0],
179-
+0x0: [ 0, 0, 0],
180-
+0x1: [ 1, 0, 0],
181-
+0x2: [ 2, 0, 0],
182-
+0x3: [ 3, 0, 0],
183-
+0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE: [~1, ~m, 0],
184-
+0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF: [~0, ~m, 0],
185-
+0x80000000000000000000000000000000: [ 0, m, 0],
186-
+0x80000000000000000000000000000001: [ 1, m, 0],
187-
]
188-
for (actual, expected) in keyValuePairs {
189-
expectEqual(expected[0], actual[0])
190-
expectEqual(expected[1], actual[1])
191-
expectEqual(expected[2], actual[2])
128+
expectEqual(expected.words[0], actual[0])
129+
expectEqual(expected.words[1], actual[1])
130+
expectEqual(expected.words[2], actual[2])
192131
}
193132
}
194133
}

0 commit comments

Comments
 (0)