@@ -13,20 +13,74 @@ extension FixedWidthInteger {
13
13
@_transparent @usableFromInline
14
14
var signExtension : Self { self &>> - 1 }
15
15
16
+ /// Saturating integer addition
17
+ ///
18
+ /// `self + other` clamped to the representable range of the type. e.g.:
19
+ /// ```
20
+ /// let a: Int8 = 84
21
+ /// let b: Int8 = 100
22
+ /// // 84 + 100 = 184 is not representable as
23
+ /// // Int8, so `c` is clamped to Int8.max (127).
24
+ /// let c = a.addingWithSaturation(b)
25
+ /// ```
26
+ ///
27
+ /// Anytime the "normal addition" `self + other` does not trap,
28
+ /// `addingWithSaturation` produces the same result.
16
29
@inlinable
17
30
public func addingWithSaturation( _ other: Self ) -> Self {
18
31
let ( wrapped, overflow) = addingReportingOverflow ( other)
19
32
if !overflow { return wrapped }
20
33
return Self . max &- signExtension
21
34
}
22
35
36
+ /// Saturating integer subtraction
37
+ ///
38
+ /// `self - other` clamped to the representable range of the type. e.g.:
39
+ /// ```
40
+ /// let a: UInt = 37
41
+ /// let b: UInt = 42
42
+ /// // 37 - 42 = -5, which is not representable as
43
+ /// // UInt, so `c` is clamped to UInt.min (zero).
44
+ /// let c = a.subtractingWithSaturation(b)
45
+ /// ```
46
+ ///
47
+ /// Note that `a.addingWithSaturation(-b)` is not always equivalent to
48
+ /// `a.subtractingWithSaturation(b)`, because `-b` is not representable
49
+ /// if `b` is the minimum value of a signed type.
50
+ ///
51
+ /// Anytime the "normal subtraction" `self - other` does not trap,
52
+ /// `subtractingWithSaturation` produces the same result.
23
53
@inlinable
24
54
public func subtractingWithSaturation( _ other: Self ) -> Self {
25
55
let ( wrapped, overflow) = subtractingReportingOverflow ( other)
26
56
if !overflow { return wrapped }
27
57
return Self . max &- signExtension
28
58
}
29
59
60
+ /// Saturating integer negation
61
+ ///
62
+ /// For unsigned types, the result is always zero. This is not very
63
+ /// interesting, but may occasionally be useful in generic contexts.
64
+ /// For signed types, the result is `-self` unless `self` is `.min`,
65
+ /// in which case the result is `.max`.
66
+ @inlinable
67
+ public func negatedWithSaturation( ) -> Self {
68
+ Self . zero. subtractingWithSaturation ( self )
69
+ }
70
+
71
+ /// Saturating integer multiplication
72
+ ///
73
+ /// `self * other` clamped to the representable range of the type. e.g.:
74
+ /// ```
75
+ /// let a: Int8 = -16
76
+ /// let b: Int8 = -8
77
+ /// // -16 * -8 = 128 is not representable as
78
+ /// // Int8, so `c` is clamped to Int8.max (127).
79
+ /// let c = a.multipliedWithSaturation(by: b)
80
+ /// ```
81
+ ///
82
+ /// Anytime the "normal multiplication" `self * other` does not trap,
83
+ /// `multipliedWithSaturation` produces the same result.
30
84
@inlinable
31
85
public func multipliedWithSaturation( by other: Self ) -> Self {
32
86
let ( high, low) = multipliedFullWidth ( by: other)
@@ -35,15 +89,29 @@ extension FixedWidthInteger {
35
89
return Self . max &- high. signExtension
36
90
}
37
91
92
+ /// Bitwise left with rounding and saturation.
93
+ ///
94
+ /// `self` multiplied by the rational number 2^(`count`), saturated to the
95
+ /// range `Self.min ... Self.max`, and rounded according to `rule`.
96
+ ///
97
+ /// See `shifted(rightBy:rounding:)` for more discussion of rounding
98
+ /// shifts with examples.
99
+ ///
100
+ /// - Parameters:
101
+ /// - leftBy count: the number of bits to shift by. If positive, this is a left-shift,
102
+ /// and if negative a right shift.
103
+ /// - rounding rule: the direction in which to round if `count` is negative.
38
104
@inlinable
39
105
public func shiftedWithSaturation< Count: BinaryInteger > (
40
106
leftBy count: Count , rounding rule: RoundingRule = . down
41
107
) -> Self {
42
108
// If count is zero or negative, negate it and do a right
43
109
// shift without saturation instead, as that's easier.
44
110
guard count > 0 else {
45
- // TODO: fixup case where 0 - count overflows
46
- return shifted ( rightBy: 0 - count, rounding: rule)
111
+ return shifted (
112
+ rightBy: Self ( clamping: count) . negatedWithSaturation ( ) ,
113
+ rounding: rule
114
+ )
47
115
}
48
116
guard count < Self . bitWidth else {
49
117
// If count is bitWidth or greater, we always overflow
0 commit comments