@@ -119,6 +119,40 @@ public func ==(a: DispatchWallTime, b: DispatchWallTime) -> Bool {
119119 return a. rawValue == b. rawValue
120120}
121121
122+ // Returns m1 * m2, clamped to the range [Int64.min, Int64.max].
123+ // Because of the way this function is used, we can always assume
124+ // that m2 > 0.
125+ private func clampedInt64Product( _ m1: Int64 , _ m2: Int64 ) -> Int64 {
126+ assert ( m2 > 0 , " multiplier must be positive " )
127+ let ( result, overflow) = m1. multipliedReportingOverflow ( by: m2)
128+ if overflow {
129+ return m1 > 0 ? Int64 . max : Int64 . min
130+ }
131+ return result
132+ }
133+
134+ // Returns its argument clamped to the range [Int64.min, Int64.max].
135+ private func toInt64Clamped( _ value: Double ) -> Int64 {
136+ if value. isNaN { return Int64 . max }
137+ if value >= Double ( Int64 . max) { return Int64 . max }
138+ if value <= Double ( Int64 . min) { return Int64 . min }
139+ return Int64 ( value)
140+ }
141+
142+ /// Represents a time interval that can be used as an offset from a `DispatchTime`
143+ /// or `DispatchWallTime`.
144+ ///
145+ /// For example:
146+ /// let inOneSecond = DispatchTime.now() + DispatchTimeInterval.seconds(1)
147+ ///
148+ /// If the requested time interval is larger then the internal representation
149+ /// permits, the result of adding it to a `DispatchTime` or `DispatchWallTime`
150+ /// is `DispatchTime.distantFuture` and `DispatchWallTime.distantFuture`
151+ /// respectively. Such time intervals compare as equal:
152+ ///
153+ /// let t1 = DispatchTimeInterval.seconds(Int.max)
154+ /// let t2 = DispatchTimeInterval.milliseconds(Int.max)
155+ /// let result = t1 == t2 // true
122156public enum DispatchTimeInterval {
123157 case seconds( Int )
124158 case milliseconds( Int )
@@ -129,9 +163,9 @@ public enum DispatchTimeInterval {
129163
130164 internal var rawValue : Int64 {
131165 switch self {
132- case . seconds( let s) : return Int64 ( s) * Int64( NSEC_PER_SEC)
133- case . milliseconds( let ms) : return Int64 ( ms) * Int64( NSEC_PER_MSEC)
134- case . microseconds( let us) : return Int64 ( us) * Int64( NSEC_PER_USEC)
166+ case . seconds( let s) : return clampedInt64Product ( Int64 ( s) , Int64 ( NSEC_PER_SEC) )
167+ case . milliseconds( let ms) : return clampedInt64Product ( Int64 ( ms) , Int64 ( NSEC_PER_MSEC) )
168+ case . microseconds( let us) : return clampedInt64Product ( Int64 ( us) , Int64 ( NSEC_PER_USEC) )
135169 case . nanoseconds( let ns) : return Int64 ( ns)
136170 case . never: return Int64 . max
137171 }
@@ -158,16 +192,12 @@ public func -(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTim
158192}
159193
160194public func + ( time: DispatchTime , seconds: Double ) -> DispatchTime {
161- let interval = seconds * Double( NSEC_PER_SEC)
162- let t = CDispatch . dispatch_time ( time. rawValue,
163- interval. isInfinite || interval. isNaN ? Int64 . max : Int64 ( interval) )
195+ let t = CDispatch . dispatch_time ( time. rawValue, toInt64Clamped ( seconds * Double( NSEC_PER_SEC) ) ) ;
164196 return DispatchTime ( rawValue: t)
165197}
166198
167199public func - ( time: DispatchTime , seconds: Double ) -> DispatchTime {
168- let interval = - seconds * Double( NSEC_PER_SEC)
169- let t = CDispatch . dispatch_time ( time. rawValue,
170- interval. isInfinite || interval. isNaN ? Int64 . min : Int64 ( interval) )
200+ let t = CDispatch . dispatch_time ( time. rawValue, toInt64Clamped ( - seconds * Double( NSEC_PER_SEC) ) ) ;
171201 return DispatchTime ( rawValue: t)
172202}
173203
@@ -182,15 +212,11 @@ public func -(time: DispatchWallTime, interval: DispatchTimeInterval) -> Dispatc
182212}
183213
184214public func + ( time: DispatchWallTime , seconds: Double ) -> DispatchWallTime {
185- let interval = seconds * Double( NSEC_PER_SEC)
186- let t = CDispatch . dispatch_time ( time. rawValue,
187- interval. isInfinite || interval. isNaN ? Int64 . max : Int64 ( interval) )
215+ let t = CDispatch . dispatch_time ( time. rawValue, toInt64Clamped ( seconds * Double( NSEC_PER_SEC) ) ) ;
188216 return DispatchWallTime ( rawValue: t)
189217}
190218
191219public func - ( time: DispatchWallTime , seconds: Double ) -> DispatchWallTime {
192- let interval = - seconds * Double( NSEC_PER_SEC)
193- let t = CDispatch . dispatch_time ( time. rawValue,
194- interval. isInfinite || interval. isNaN ? Int64 . min : Int64 ( interval) )
220+ let t = CDispatch . dispatch_time ( time. rawValue, toInt64Clamped ( - seconds * Double( NSEC_PER_SEC) ) ) ;
195221 return DispatchWallTime ( rawValue: t)
196222}
0 commit comments