Skip to content

Commit 1149eea

Browse files
committed
Incorporate feedback from @moiseev
- Also clean up some 80-column issues - And improve some tests from before literal expressibility
1 parent 237d877 commit 1149eea

File tree

2 files changed

+141
-127
lines changed

2 files changed

+141
-127
lines changed

stdlib/public/core/Integers.swift.gyb

Lines changed: 53 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,9 +1342,6 @@ public protocol BinaryInteger :
13421342
Hashable, Numeric, CustomStringConvertible, Strideable
13431343
where Magnitude : BinaryInteger, Magnitude.Magnitude == Magnitude
13441344
{
1345-
// FIXME(ABI) (Recursive Protocol Constraints): should add:
1346-
// where Magnitude : BinaryInteger
1347-
13481345
/// A Boolean value indicating whether this type is a signed integer type.
13491346
///
13501347
/// *Signed* integer types can represent both positive and negative values.
@@ -2929,6 +2926,7 @@ ${assignmentOperatorComment(x.operator, True)}
29292926
}
29302927

29312928
/// A representation of this integer with the byte order swapped.
2929+
@_transparent
29322930
public var byteSwapped: ${Self} {
29332931
% if bits <= 8:
29342932
return self
@@ -3186,10 +3184,10 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
31863184
self.init((0, 0))
31873185
}
31883186

3189-
// integer
3187+
// BinaryInteger
31903188
//
31913189
public var magnitude: DoubleWidth<Low> {
3192-
if Base.isSigned && _storage.high < 0 {
3190+
if Base.isSigned && _storage.high < (0 as High) {
31933191
return self == .min
31943192
? DoubleWidth.max.magnitude &+ 1
31953193
: (0 - self).magnitude
@@ -3216,18 +3214,18 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
32163214
}
32173215
return lhs._storage.low < rhs._storage.low
32183216
}
3219-
3217+
32203218
public init<T : BinaryInteger>(_ source: T) {
32213219
self.init(exactly: source)!
32223220
}
32233221

32243222
public init?<T : BinaryInteger>(exactly source: T) {
32253223
// Can't represent a negative 'source' if Base is unsigned
3226-
guard source >= 0 || DoubleWidth<Base>.isSigned else { return nil }
3224+
guard source >= 0 || DoubleWidth.isSigned else { return nil }
32273225

32283226
// Is 'source' is entirely representable in Low?
32293227
if let low = Low(exactly: source.magnitude) {
3230-
if source < 0 {
3228+
if source < (0 as T) {
32313229
self.init((~0, ~low + 1))
32323230
} else {
32333231
self.init((0, low))
@@ -3243,7 +3241,7 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
32433241
self.init((high, low))
32443242
}
32453243
}
3246-
3244+
32473245
public init<T : FloatingPoint>(_ source: T) {
32483246
fatalError()
32493247
}
@@ -3255,18 +3253,17 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
32553253
public init<T : BinaryFloatingPoint>(_ source: T)
32563254
where T.RawSignificand : FixedWidthInteger
32573255
{
3258-
assert(source.isFinite, "Can't create a DoubleWidth<\(Base.self)> from infinity")
3259-
assert(!source.isNaN, "Can't create a DoubleWidth<\(Base.self)> from a NaN")
3256+
_precondition(source.isFinite, "Can't create a DoubleWidth from a non-finite value")
32603257
self.init(exactly: source.rounded(.towardZero))!
32613258
}
32623259

32633260
public init?<T : BinaryFloatingPoint>(exactly source: T)
32643261
where T.RawSignificand : FixedWidthInteger
32653262
{
32663263
// Need a finite value
3267-
guard source.isFinite && !source.isNaN else { return nil }
3264+
guard source.isFinite else { return nil }
32683265

3269-
// Don't need to go further with zero
3266+
// Don't need to go further with zero.
32703267
if source.isZero {
32713268
self.init(0)
32723269
return
@@ -3276,28 +3273,29 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
32763273
guard source.exponent >= 0 else { return nil }
32773274

32783275
typealias Raw = T.RawSignificand
3279-
let bitPattern: Raw = source.significandBitPattern | ((1 as Raw) &<< Raw(T.significandBitCount))
3280-
let offset: Int = T.significandBitCount - Int(source.exponent)
3276+
let bitPattern = source.significandBitPattern |
3277+
((1 as Raw) &<< Raw(T.significandBitCount))
3278+
let offset = T.significandBitCount - Int(source.exponent)
32813279

32823280
// FIXME: spurious compile error when 'where' clause above is removed:
32833281
// error: non-nominal type 'T.RawSignificand' does not support explicit initialization
3284-
let fractionPart: Raw = bitPattern &<< Raw(Int(Raw.bitWidth - offset))
3282+
let fractionPart: Raw = bitPattern &<< Raw(Raw.bitWidth - offset)
32853283
guard fractionPart == 0 else {
32863284
return nil
32873285
}
32883286

32893287
let integerPart: Raw = bitPattern &>> Raw(offset)
32903288

3291-
// Exit early for zero
3292-
guard integerPart > 0 else {
3293-
self.init(0)
3294-
return
3295-
}
3289+
// Should have caught any actual zero values above
3290+
_sanityCheck(integerPart > (0 as Raw))
32963291

32973292
if source.sign == .minus {
32983293
if !DoubleWidth.isSigned || integerPart &- 1 > DoubleWidth.max {
32993294
return nil
33003295
}
3296+
// Have to juggle, or else the intermediate step of creating a value
3297+
// with Self.min's magnitude will overflow. It's okay to use wrapping
3298+
// subtraction because integerPart > 0.
33013299
self.init(integerPart &- 1)
33023300
self = 0 &- self &- 1
33033301
} else {
@@ -3311,20 +3309,22 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
33113309
fatalError("word(at:) is not supported on this type")
33123310
}
33133311
if n > 0 {
3312+
// Since `Base` is narrower than word, any non-zero word will give us
3313+
// the correct value here (0 or ~0).
33143314
return _storage.high._word(at: n)
33153315
}
3316-
return _storage.low._word(at: 0) | _storage.high._word(at: 0) << numericCast(Base.bitWidth)
3316+
return _storage.low._word(at: 0) |
3317+
(_storage.high._word(at: 0) << numericCast(Base.bitWidth))
33173318
} else {
33183319
// multiples of ${word_bits} only
33193320
if Base.bitWidth % ${word_bits} != 0 {
33203321
fatalError("word(at:) is not supported on this type")
33213322
}
33223323

33233324
// TODO: move to Int128 just like init(_builtinIntegerLiteral:) ?
3324-
let wordsInBase = Base.bitWidth / ${word_bits}
3325-
return (n < wordsInBase) ?
3325+
return (n < _storage.low.countRepresentedWords) ?
33263326
_storage.low._word(at: n) :
3327-
_storage.high._word(at: n - wordsInBase)
3327+
_storage.high._word(at: n - _storage.low.countRepresentedWords)
33283328
}
33293329
}
33303330

@@ -3356,7 +3356,7 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
33563356
let (high, highOverflow) =
33573357
_storage.high.${x.name}ReportingOverflow(rhs._storage.high)
33583358
let isLowOverflow = lowOverflow == .overflow
3359-
let result = (high &${x.operator} (isLowOverflow ? High(1) : High(0)), low)
3359+
let result = (high &${x.operator} (isLowOverflow ? 1 : 0), low)
33603360
let overflow = ArithmeticOverflow(
33613361
highOverflow == .overflow ||
33623362
high == ${highAffectedByLowOverflow} && isLowOverflow
@@ -3372,7 +3372,7 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
33723372
let (carry, product) = multipliedFullWidth(by: rhs)
33733373
let result = DoubleWidth(extendingOrTruncating: product)
33743374

3375-
let isNegative = (self < 0) != (rhs < 0)
3375+
let isNegative = (self < (0 as DoubleWidth)) != (rhs < (0 as DoubleWidth))
33763376
let didCarry = isNegative ? carry != ~0 : carry != 0
33773377
let hadPositiveOverflow = !isNegative &&
33783378
DoubleWidth.isSigned && product.leadingZeroBitCount == 0
@@ -3382,7 +3382,7 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
33823382

33833383
public func quotientAndRemainder(dividingBy other: DoubleWidth)
33843384
-> (quotient: DoubleWidth, remainder: DoubleWidth) {
3385-
let isNegative = (self < 0) != (other < 0)
3385+
let isNegative = (self < (0 as DoubleWidth)) != (other < (0 as DoubleWidth))
33863386

33873387
let rhs = other.magnitude
33883388
var q = self.magnitude
@@ -3394,8 +3394,10 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
33943394

33953395
// Calculate the number of bits before q and rhs line up,
33963396
// we can skip that many bits of iteration.
3397-
let initialOffset = q.leadingZeroBitCount + (DoubleWidth.bitWidth - rhs.leadingZeroBitCount) - 1
3397+
let initialOffset = q.leadingZeroBitCount +
3398+
(DoubleWidth.bitWidth - rhs.leadingZeroBitCount) - 1
33983399

3400+
// TODO(performance): Use &>> instead here?
33993401
// Start with remainder capturing the high bits of q.
34003402
var r = q >> Magnitude(DoubleWidth.bitWidth - initialOffset)
34013403
q <<= Magnitude(initialOffset)
@@ -3415,7 +3417,7 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
34153417
}
34163418

34173419
// Sign of remainder matches dividend
3418-
let remainder = self < 0
3420+
let remainder = self < (0 as DoubleWidth)
34193421
? 0 - DoubleWidth(r)
34203422
: DoubleWidth(r)
34213423

@@ -3428,7 +3430,7 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
34283430

34293431
public func dividedReportingOverflow(by other: DoubleWidth)
34303432
-> (partialValue: DoubleWidth, overflow: ArithmeticOverflow) {
3431-
if other == 0 || (other < 0 && self == .min) {
3433+
if other == 0 || (DoubleWidth.isSigned && other == -1 && self == .min) {
34323434
return (self, .overflow)
34333435
}
34343436

@@ -3437,7 +3439,7 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
34373439

34383440
public func remainderReportingOverflow(dividingBy other: DoubleWidth)
34393441
-> (partialValue: DoubleWidth, overflow: ArithmeticOverflow) {
3440-
if other == 0 {
3442+
if other == 0 || (DoubleWidth.isSigned && other == -1 && self == .min) {
34413443
return (self, .overflow)
34423444
}
34433445

@@ -3446,7 +3448,8 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
34463448

34473449
public func multipliedFullWidth(by other: DoubleWidth)
34483450
-> (high: DoubleWidth, low: DoubleWidth.Magnitude) {
3449-
let isNegative = DoubleWidth.isSigned && (self < DoubleWidth()) != (other < DoubleWidth())
3451+
let isNegative = DoubleWidth.isSigned &&
3452+
(self < (0 as DoubleWidth)) != (other < (0 as DoubleWidth))
34503453

34513454
func mul(_ x: Low, _ y: Low) -> (partial: Low, carry: Low) {
34523455
let (high, low) = x.multipliedFullWidth(by: y)
@@ -3473,7 +3476,8 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
34733476
let mid2 = sum(b.carry, c.carry, d.partial)
34743477

34753478
let low = DoubleWidth<Low>((mid1.partial, a.partial))
3476-
let high = DoubleWidth((High(mid2.carry + d.carry), mid1.carry + mid2.partial))
3479+
let high = DoubleWidth(
3480+
(High(mid2.carry + d.carry), mid1.carry + mid2.partial))
34773481

34783482
if isNegative {
34793483
let (lowComplement, overflow) = (~low).addingReportingOverflow(1)
@@ -3504,41 +3508,41 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
35043508
% end
35053509

35063510
public static func <<=(lhs: inout DoubleWidth, rhs: DoubleWidth) {
3507-
if rhs < DoubleWidth((0, 0)) {
3508-
lhs >>= DoubleWidth((0, 0)) - rhs
3511+
if rhs < (0 as DoubleWidth) {
3512+
lhs >>= 0 - rhs
35093513
return
35103514
}
35113515

3512-
if rhs._storage.high != 0 as High || rhs._storage.low >= DoubleWidth.bitWidth {
3513-
lhs = DoubleWidth((0, 0))
3516+
if rhs._storage.high != 0 || rhs._storage.low >= DoubleWidth.bitWidth {
3517+
lhs = 0
35143518
return
35153519
}
35163520

35173521
// Shift is exactly the width of `Base`, so low -> high.
3518-
if Int(rhs._storage.low) == Base.bitWidth {
3519-
lhs = DoubleWidth((High(extendingOrTruncating: lhs._storage.low), numericCast(0)))
3522+
if rhs._storage.low == Base.bitWidth {
3523+
lhs = DoubleWidth((High(extendingOrTruncating: lhs._storage.low), 0))
35203524
return
35213525
}
35223526

35233527
lhs &<<= rhs
35243528
}
35253529

35263530
public static func >>=(lhs: inout DoubleWidth, rhs: DoubleWidth) {
3527-
if rhs < DoubleWidth((0, 0)) {
3528-
lhs <<= DoubleWidth((0, 0)) - rhs
3531+
if rhs < (0 as DoubleWidth) {
3532+
lhs <<= 0 - rhs
35293533
return
35303534
}
35313535

35323536
// Shift is larger than this type's bit width.
3533-
if rhs._storage.high != 0 as High || rhs._storage.low >= DoubleWidth.bitWidth {
3534-
lhs = lhs < 0 ? ~0 : 0
3537+
if rhs._storage.high != 0 || rhs._storage.low >= DoubleWidth.bitWidth {
3538+
lhs = lhs < (0 as DoubleWidth) ? ~0 : 0
35353539
return
35363540
}
35373541

35383542
// Shift is exactly the width of `Base`, so high -> low.
3539-
if rhs._storage.low == numericCast(Base.bitWidth) {
3543+
if rhs._storage.low == Base.bitWidth {
35403544
lhs = DoubleWidth(
3541-
(lhs < 0 ? ~0 : 0, Low(extendingOrTruncating: lhs._storage.high)))
3545+
(lhs < (0 as DoubleWidth) ? ~0 : 0, Low(extendingOrTruncating: lhs._storage.high)))
35423546
return
35433547
}
35443548

@@ -3602,8 +3606,8 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
36023606
// other
36033607
//
36043608
public init(_builtinIntegerLiteral x: _MaxBuiltinIntegerType) {
3605-
// FIXME: This won't work if `x` is out of range for `Int`
3606-
self.init(Int(_builtinIntegerLiteral: x))
3609+
// FIXME: This won't work if `x` is out of range for `Int64`
3610+
self.init(Int64(_builtinIntegerLiteral: x))
36073611
}
36083612

36093613
public var description: String {
@@ -3630,6 +3634,7 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
36303634
return _mixInt(high.hashValue) ^ low.hashValue
36313635
}
36323636

3637+
@_transparent
36333638
public var byteSwapped: DoubleWidth {
36343639
return DoubleWidth((High(extendingOrTruncating: low.byteSwapped),
36353640
Low(extendingOrTruncating: high.byteSwapped)))

0 commit comments

Comments
 (0)