@@ -16,6 +16,8 @@ internal import _ForSwiftFoundation
16
16
internal struct ProgressFraction : Sendable , Equatable , CustomDebugStringConvertible {
17
17
var completed : Int
18
18
var total : Int ?
19
+ /// Indicates whether mathematical operations on this fraction have exceeded integer limits,
20
+ /// causing the fraction to fall back to floating-point representation for accuracy.
19
21
private( set) var overflowed : Bool
20
22
21
23
init ( ) {
@@ -69,7 +71,13 @@ internal struct ProgressFraction : Sendable, Equatable, CustomDebugStringConvert
69
71
}
70
72
}
71
73
72
- static private func _math( lhs: ProgressFraction , rhs: ProgressFraction , whichOperator: ( _ lhs : Double , _ rhs : Double ) -> Double , whichOverflow : ( _ lhs: Int , _ rhs: Int ) -> ( Int , overflow: Bool ) ) -> ProgressFraction {
74
+ /// A closure that performs floating-point arithmetic operations
75
+ private typealias FloatingPointOperation = ( _ lhs: Double , _ rhs: Double ) -> Double
76
+
77
+ /// A closure that performs integer arithmetic operations with overflow detection
78
+ private typealias OverflowReportingOperation = ( _ lhs: Int , _ rhs: Int ) -> ( Int , overflow: Bool )
79
+
80
+ static private func _math( lhs: ProgressFraction , rhs: ProgressFraction , operation: FloatingPointOperation , overflowOperation: OverflowReportingOperation ) -> ProgressFraction {
73
81
// Mathematically, it is nonsense to add or subtract something with a denominator of 0. However, for the purposes of implementing Progress' fractions, we just assume that a zero-denominator fraction is "weightless" and return the other value. We still need to check for the case where they are both nonsense though.
74
82
precondition ( !( lhs. total == 0 && rhs. total == 0 ) , " Attempt to add or subtract invalid fraction " )
75
83
guard let lhsTotal = lhs. total, lhsTotal != 0 else {
@@ -81,14 +89,14 @@ internal struct ProgressFraction : Sendable, Equatable, CustomDebugStringConvert
81
89
82
90
guard !lhs. overflowed && !rhs. overflowed else {
83
91
// If either has overflowed already, we preserve that
84
- return ProgressFraction ( double: whichOperator ( lhs. fractionCompleted, rhs. fractionCompleted) , overflow: true )
92
+ return ProgressFraction ( double: operation ( lhs. fractionCompleted, rhs. fractionCompleted) , overflow: true )
85
93
}
86
94
87
95
//TODO: rdar://148758226 Overflow check
88
96
if let lcm = _leastCommonMultiple ( lhsTotal, rhsTotal) {
89
- let result = whichOverflow ( lhs. completed * ( lcm / lhsTotal) , rhs. completed * ( lcm / rhsTotal) )
97
+ let result = overflowOperation ( lhs. completed * ( lcm / lhsTotal) , rhs. completed * ( lcm / rhsTotal) )
90
98
if result. overflow {
91
- return ProgressFraction ( double: whichOperator ( lhs. fractionCompleted, rhs. fractionCompleted) , overflow: true )
99
+ return ProgressFraction ( double: operation ( lhs. fractionCompleted, rhs. fractionCompleted) , overflow: true )
92
100
} else {
93
101
return ProgressFraction ( completed: result. 0 , total: lcm)
94
102
}
@@ -102,30 +110,30 @@ internal struct ProgressFraction : Sendable, Equatable, CustomDebugStringConvert
102
110
let lhsSimplifiedTotal = lhsSimplified. total,
103
111
let rhsSimplifiedTotal = rhsSimplified. total else {
104
112
// Simplification failed, fall back to double math
105
- return ProgressFraction ( double: whichOperator ( lhs. fractionCompleted, rhs. fractionCompleted) , overflow: true )
113
+ return ProgressFraction ( double: operation ( lhs. fractionCompleted, rhs. fractionCompleted) , overflow: true )
106
114
}
107
115
108
116
if let lcm = _leastCommonMultiple ( lhsSimplifiedTotal, rhsSimplifiedTotal) {
109
- let result = whichOverflow ( lhsSimplified. completed * ( lcm / lhsSimplifiedTotal) , rhsSimplified. completed * ( lcm / rhsSimplifiedTotal) )
117
+ let result = overflowOperation ( lhsSimplified. completed * ( lcm / lhsSimplifiedTotal) , rhsSimplified. completed * ( lcm / rhsSimplifiedTotal) )
110
118
if result. overflow {
111
119
// Use original lhs/rhs here
112
- return ProgressFraction ( double: whichOperator ( lhs. fractionCompleted, rhs. fractionCompleted) , overflow: true )
120
+ return ProgressFraction ( double: operation ( lhs. fractionCompleted, rhs. fractionCompleted) , overflow: true )
113
121
} else {
114
122
return ProgressFraction ( completed: result. 0 , total: lcm)
115
123
}
116
124
} else {
117
125
// Still overflow
118
- return ProgressFraction ( double: whichOperator ( lhs. fractionCompleted, rhs. fractionCompleted) , overflow: true )
126
+ return ProgressFraction ( double: operation ( lhs. fractionCompleted, rhs. fractionCompleted) , overflow: true )
119
127
}
120
128
}
121
129
}
122
130
123
131
static internal func + ( lhs: ProgressFraction , rhs: ProgressFraction ) -> ProgressFraction {
124
- return _math ( lhs: lhs, rhs: rhs, whichOperator : + , whichOverflow : { $0. addingReportingOverflow ( $1) } )
132
+ return _math ( lhs: lhs, rhs: rhs, operation : + , overflowOperation : { $0. addingReportingOverflow ( $1) } )
125
133
}
126
134
127
135
static internal func - ( lhs: ProgressFraction , rhs: ProgressFraction ) -> ProgressFraction {
128
- return _math ( lhs: lhs, rhs: rhs, whichOperator : - , whichOverflow : { $0. subtractingReportingOverflow ( $1) } )
136
+ return _math ( lhs: lhs, rhs: rhs, operation : - , overflowOperation : { $0. subtractingReportingOverflow ( $1) } )
129
137
}
130
138
131
139
static internal func * ( lhs: ProgressFraction , rhs: ProgressFraction ) -> ProgressFraction ? {
0 commit comments