@@ -123,6 +123,40 @@ extension DispatchWallTime {
123123 }
124124}
125125
126+ // Returns m1 * m2, clamped to the range [Int64.min, Int64.max].
127+ // Because of the way this function is used, we can always assume
128+ // that m2 > 0.
129+ private func clampedInt64Product( _ m1: Int64 , _ m2: Int64 ) -> Int64 {
130+ assert ( m2 > 0 , " multiplier must be positive " )
131+ let ( result, overflow) = m1. multipliedReportingOverflow ( by: m2)
132+ if overflow {
133+ return m1 > 0 ? Int64 . max : Int64 . min
134+ }
135+ return result
136+ }
137+
138+ // Returns its argument clamped to the range [Int64.min, Int64.max].
139+ private func toInt64Clamped( _ value: Double ) -> Int64 {
140+ if value. isNaN { return Int64 . max }
141+ if value >= Double ( Int64 . max) { return Int64 . max }
142+ if value <= Double ( Int64 . min) { return Int64 . min }
143+ return Int64 ( value)
144+ }
145+
146+ /// Represents a time interval that can be used as an offset from a `DispatchTime`
147+ /// or `DispatchWallTime`.
148+ ///
149+ /// For example:
150+ /// let inOneSecond = DispatchTime.now() + DispatchTimeInterval.seconds(1)
151+ ///
152+ /// If the requested time interval is larger then the internal representation
153+ /// permits, the result of adding it to a `DispatchTime` or `DispatchWallTime`
154+ /// is `DispatchTime.distantFuture` and `DispatchWallTime.distantFuture`
155+ /// respectively. Such time intervals compare as equal:
156+ ///
157+ /// let t1 = DispatchTimeInterval.seconds(Int.max)
158+ /// let t2 = DispatchTimeInterval.milliseconds(Int.max)
159+ /// let result = t1 == t2 // true
126160public enum DispatchTimeInterval {
127161 case seconds( Int )
128162 case milliseconds( Int )
@@ -133,9 +167,9 @@ public enum DispatchTimeInterval {
133167
134168 internal var rawValue : Int64 {
135169 switch self {
136- case . seconds( let s) : return Int64 ( s) * Int64( NSEC_PER_SEC)
137- case . milliseconds( let ms) : return Int64 ( ms) * Int64( NSEC_PER_MSEC)
138- case . microseconds( let us) : return Int64 ( us) * Int64( NSEC_PER_USEC)
170+ case . seconds( let s) : return clampedInt64Product ( Int64 ( s) , Int64 ( NSEC_PER_SEC) )
171+ case . milliseconds( let ms) : return clampedInt64Product ( Int64 ( ms) , Int64 ( NSEC_PER_MSEC) )
172+ case . microseconds( let us) : return clampedInt64Product ( Int64 ( us) , Int64 ( NSEC_PER_USEC) )
139173 case . nanoseconds( let ns) : return Int64 ( ns)
140174 case . never: return Int64 . max
141175 }
@@ -162,16 +196,12 @@ public func -(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTim
162196}
163197
164198public func + ( time: DispatchTime , seconds: Double ) -> DispatchTime {
165- let interval = seconds * Double( NSEC_PER_SEC)
166- let t = CDispatch . dispatch_time ( time. rawValue,
167- interval. isInfinite || interval. isNaN ? Int64 . max : Int64 ( interval) )
199+ let t = CDispatch . dispatch_time ( time. rawValue, toInt64Clamped ( seconds * Double( NSEC_PER_SEC) ) ) ;
168200 return DispatchTime ( rawValue: t)
169201}
170202
171203public func - ( time: DispatchTime , seconds: Double ) -> DispatchTime {
172- let interval = - seconds * Double( NSEC_PER_SEC)
173- let t = CDispatch . dispatch_time ( time. rawValue,
174- interval. isInfinite || interval. isNaN ? Int64 . min : Int64 ( interval) )
204+ let t = CDispatch . dispatch_time ( time. rawValue, toInt64Clamped ( - seconds * Double( NSEC_PER_SEC) ) ) ;
175205 return DispatchTime ( rawValue: t)
176206}
177207
@@ -186,15 +216,11 @@ public func -(time: DispatchWallTime, interval: DispatchTimeInterval) -> Dispatc
186216}
187217
188218public func + ( time: DispatchWallTime , seconds: Double ) -> DispatchWallTime {
189- let interval = seconds * Double( NSEC_PER_SEC)
190- let t = CDispatch . dispatch_time ( time. rawValue,
191- interval. isInfinite || interval. isNaN ? Int64 . max : Int64 ( interval) )
219+ let t = CDispatch . dispatch_time ( time. rawValue, toInt64Clamped ( seconds * Double( NSEC_PER_SEC) ) ) ;
192220 return DispatchWallTime ( rawValue: t)
193221}
194222
195223public func - ( time: DispatchWallTime , seconds: Double ) -> DispatchWallTime {
196- let interval = - seconds * Double( NSEC_PER_SEC)
197- let t = CDispatch . dispatch_time ( time. rawValue,
198- interval. isInfinite || interval. isNaN ? Int64 . min : Int64 ( interval) )
224+ let t = CDispatch . dispatch_time ( time. rawValue, toInt64Clamped ( - seconds * Double( NSEC_PER_SEC) ) ) ;
199225 return DispatchWallTime ( rawValue: t)
200226}
0 commit comments