@@ -16,6 +16,8 @@ internal import _ForSwiftFoundation
1616internal struct ProgressFraction : Sendable , Equatable , CustomDebugStringConvertible {
1717 var completed : Int
1818 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.
1921 private( set) var overflowed : Bool
2022
2123 init ( ) {
@@ -69,7 +71,13 @@ internal struct ProgressFraction : Sendable, Equatable, CustomDebugStringConvert
6971 }
7072 }
7173
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 {
7381 // 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.
7482 precondition ( !( lhs. total == 0 && rhs. total == 0 ) , " Attempt to add or subtract invalid fraction " )
7583 guard let lhsTotal = lhs. total, lhsTotal != 0 else {
@@ -81,14 +89,14 @@ internal struct ProgressFraction : Sendable, Equatable, CustomDebugStringConvert
8189
8290 guard !lhs. overflowed && !rhs. overflowed else {
8391 // 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 )
8593 }
8694
8795 //TODO: rdar://148758226 Overflow check
8896 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) )
9098 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 )
92100 } else {
93101 return ProgressFraction ( completed: result. 0 , total: lcm)
94102 }
@@ -102,30 +110,30 @@ internal struct ProgressFraction : Sendable, Equatable, CustomDebugStringConvert
102110 let lhsSimplifiedTotal = lhsSimplified. total,
103111 let rhsSimplifiedTotal = rhsSimplified. total else {
104112 // 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 )
106114 }
107115
108116 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) )
110118 if result. overflow {
111119 // 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 )
113121 } else {
114122 return ProgressFraction ( completed: result. 0 , total: lcm)
115123 }
116124 } else {
117125 // Still overflow
118- return ProgressFraction ( double: whichOperator ( lhs. fractionCompleted, rhs. fractionCompleted) , overflow: true )
126+ return ProgressFraction ( double: operation ( lhs. fractionCompleted, rhs. fractionCompleted) , overflow: true )
119127 }
120128 }
121129 }
122130
123131 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) } )
125133 }
126134
127135 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) } )
129137 }
130138
131139 static internal func * ( lhs: ProgressFraction , rhs: ProgressFraction ) -> ProgressFraction ? {
0 commit comments