@@ -53,15 +53,6 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
5353 var otherProperties : [ AnyMetatypeWrapper : ( any Sendable ) ]
5454 // Type: Metatype maps to dictionary of child to value
5555 var childrenOtherProperties : [ AnyMetatypeWrapper : OrderedDictionary < ProgressManager , [ ( any Sendable ) ] > ]
56-
57- // dirty bit for completed count
58- var isDirtyCompleted : Bool
59- var updatedCompletedCount : Int
60-
61- // dirty bit for total count
62- var isDirtyTotal : Bool
63- var updatedTotalCount : Int ?
64-
6556 var children : Set < ProgressManager >
6657 }
6758
@@ -87,10 +78,7 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
8778 public var totalCount : Int ? {
8879 _ $observationRegistrar. access ( self , keyPath: \. totalCount)
8980 return state. withLock { state in
90- if state. isDirtyTotal {
91- updateDirtiedValues ( state: & state)
92- }
93- return getTotalCount ( fractionState: & state. fractionState)
81+ getTotalCount ( fractionState: & state. fractionState)
9482 }
9583 }
9684
@@ -99,10 +87,7 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
9987 public var completedCount : Int {
10088 _ $observationRegistrar. access ( self , keyPath: \. completedCount)
10189 return state. withLock { state in
102- if state. isDirtyCompleted {
103- updateDirtiedValues ( state: & state)
104- }
105- return getCompletedCount ( fractionState: & state. fractionState)
90+ getCompletedCount ( fractionState: & state. fractionState)
10691 }
10792 }
10893
@@ -112,10 +97,7 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
11297 public var fractionCompleted : Double {
11398 _ $observationRegistrar. access ( self , keyPath: \. fractionCompleted)
11499 return state. withLock { state in
115- if state. isDirtyTotal || state. isDirtyCompleted {
116- updateDirtiedValues ( state: & state)
117- }
118- return getFractionCompleted ( fractionState: & state. fractionState)
100+ getFractionCompleted ( fractionState: & state. fractionState)
119101 }
120102 }
121103
@@ -124,12 +106,7 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
124106 public var isIndeterminate : Bool {
125107 _ $observationRegistrar. access ( self , keyPath: \. isIndeterminate)
126108 return state. withLock { state in
127- if state. isDirtyTotal {
128- if state. isDirtyTotal || state. isDirtyCompleted {
129- updateDirtiedValues ( state: & state)
130- }
131- }
132- return getIsIndeterminate ( fractionState: & state. fractionState)
109+ getIsIndeterminate ( fractionState: & state. fractionState)
133110 }
134111 }
135112
@@ -138,47 +115,7 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
138115 public var isFinished : Bool {
139116 _ $observationRegistrar. access ( self , keyPath: \. isFinished)
140117 return state. withLock { state in
141- if state. isDirtyTotal || state. isDirtyCompleted {
142- updateDirtiedValues ( state: & state)
143- }
144- return getIsFinished ( fractionState: & state. fractionState)
145- }
146- }
147-
148- /// This is called if the total dirty bit is set
149- private func updateDirtiedValues( state: inout State ) {
150- if state. children. isEmpty {
151- // If there are no children, update value directly and don't traverse down anymore
152- let updateState = getPreviousAndCurrentState ( state: & state)
153- updateFractionCompleted ( from: updateState. previous, to: updateState. current)
154-
155- // mark dirty bit false
156- state. isDirtyTotal = false
157- state. isDirtyCompleted = false
158- } else {
159- // If there are children, traverse down
160- for child in state. children {
161- child. updateDirtiedValues ( )
162- }
163- }
164- }
165-
166- private func updateDirtiedValues( ) {
167- state. withLock { state in
168- if state. children. isEmpty {
169- // If there are no children, update value directly and don't traverse down anymore
170- let updateState = getPreviousAndCurrentState ( state: & state)
171- updateFractionCompleted ( from: updateState. previous, to: updateState. current)
172-
173- // mark dirty bit false
174- state. isDirtyTotal = false
175- state. isDirtyCompleted = false
176- } else {
177- // If there are children, traverse down
178- for child in state. children {
179- child. updateDirtiedValues ( )
180- }
181- }
118+ getIsFinished ( fractionState: & state. fractionState)
182119 }
183120 }
184121
@@ -204,17 +141,24 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
204141 /// The total units of work.
205142 public var totalCount : Int ? {
206143 mutating get {
207- if state. isDirtyTotal {
208- manager. updateDirtiedValues ( state: & state)
209- }
210- return manager. getTotalCount ( fractionState: & state. fractionState)
144+ manager. getTotalCount ( fractionState: & state. fractionState)
211145 }
212146
213147 set {
214- state. updatedTotalCount = newValue
215- manager. markTotalDirty ( state: & state)
216-
217- // Interop updates stuff
148+ let previous = state. fractionState. overallFraction
149+ if state. fractionState. selfFraction. total != newValue && state. fractionState. selfFraction. total > 0 {
150+ state. fractionState. childFraction = state. fractionState. childFraction * _ProgressFraction( completed: state. fractionState. selfFraction. total, total: newValue ?? 1 )
151+ }
152+ state. fractionState. selfFraction. total = newValue ?? 0
153+
154+ // if newValue is nil, reset indeterminate to true
155+ if newValue != nil {
156+ state. fractionState. indeterminate = false
157+ } else {
158+ state. fractionState. indeterminate = true
159+ }
160+ //TODO: rdar://149015734 Check throttling
161+ manager. updateFractionCompleted ( from: previous, to: state. fractionState. overallFraction)
218162 manager. ghostReporter? . notifyObservers ( with: . totalCountUpdated)
219163 manager. monitorInterop. withLock { [ manager] interop in
220164 if interop == true {
@@ -228,17 +172,15 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
228172 /// The completed units of work.
229173 public var completedCount : Int {
230174 mutating get {
231- if state. isDirtyCompleted {
232- manager. updateDirtiedValues ( state: & state)
233- }
234- return manager. getCompletedCount ( fractionState: & state. fractionState)
175+ manager. getCompletedCount ( fractionState: & state. fractionState)
235176 }
236177
237178 set {
238- state . updatedCompletedCount = newValue
239- manager . markCompletedDirty ( state: & state )
240-
179+ let prev = state . fractionState . overallFraction
180+ state. fractionState . selfFraction . completed = newValue
181+ manager . updateFractionCompleted ( from : prev , to : state . fractionState . overallFraction )
241182 manager. ghostReporter? . notifyObservers ( with: . fractionUpdated)
183+
242184 manager. monitorInterop. withLock { [ manager] interop in
243185 if interop == true {
244186 manager. notifyObservers ( with: . fractionUpdated)
@@ -293,14 +235,7 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
293235 childFraction: _ProgressFraction ( completed: 0 , total: 1 ) ,
294236 interopChild: nil
295237 )
296- let state = State ( fractionState: fractionState,
297- otherProperties: [ : ] ,
298- childrenOtherProperties: [ : ] ,
299- isDirtyCompleted: false ,
300- updatedCompletedCount: 0 ,
301- isDirtyTotal: false ,
302- updatedTotalCount: 0 ,
303- children: Set ( ) )
238+ let state = State ( fractionState: fractionState, otherProperties: [ : ] , childrenOtherProperties: [ : ] , children: Set ( ) )
304239 self . state = LockedState ( initialState: state)
305240 self . interopObservation = interopObservation
306241 self . ghostReporter = ghostReporter
@@ -314,6 +249,34 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
314249 self . init ( total: totalCount, ghostReporter: nil , interopObservation: nil )
315250 }
316251
252+ /// Sets `totalCount`.
253+ /// - Parameter newTotal: Total units of work.
254+ public func setTotalCount( _ newTotal: Int ? ) {
255+ state. withLock { state in
256+ let previous = state. fractionState. overallFraction
257+ if state. fractionState. selfFraction. total != newTotal && state. fractionState. selfFraction. total > 0 {
258+ state. fractionState. childFraction = state. fractionState. childFraction * _ProgressFraction( completed: state. fractionState. selfFraction. total, total: newTotal ?? 1 )
259+ }
260+ state. fractionState. selfFraction. total = newTotal ?? 0
261+
262+ // if newValue is nil, reset indeterminate to true
263+ if newTotal != nil {
264+ state. fractionState. indeterminate = false
265+ } else {
266+ state. fractionState. indeterminate = true
267+ }
268+ updateFractionCompleted ( from: previous, to: state. fractionState. overallFraction)
269+
270+ ghostReporter? . notifyObservers ( with: . totalCountUpdated)
271+
272+ monitorInterop. withLock { [ self ] interop in
273+ if interop == true {
274+ notifyObservers ( with: . totalCountUpdated)
275+ }
276+ }
277+ }
278+ }
279+
317280 /// Returns a `Subprogress` representing a portion of `self` which can be passed to any method that reports progress.
318281 ///
319282 /// - Parameter count: Units, which is a portion of `totalCount`delegated to an instance of `Subprogress`.
@@ -343,10 +306,8 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
343306 /// Increases `completedCount` by `count`.
344307 /// - Parameter count: Units of work.
345308 public func complete( count: Int ) {
346- state. withLock { state in
347- state. updatedCompletedCount = state. fractionState. selfFraction. completed + count
348- markCompletedDirty ( state: & state)
349- }
309+ let updateState = updateCompletedCount ( count: count)
310+ updateFractionCompleted ( from: updateState. previous, to: updateState. current)
350311
351312 // Interop updates stuff
352313 ghostReporter? . notifyObservers ( with: . fractionUpdated)
@@ -382,16 +343,7 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
382343 return try state. withLock { state in
383344 var values = Values ( manager: self , state: state)
384345 // This is done to avoid copy on write later
385- state = State ( fractionState: FractionState ( indeterminate: true ,
386- selfFraction: _ProgressFraction ( ) ,
387- childFraction: _ProgressFraction ( ) ) ,
388- otherProperties: [ : ] ,
389- childrenOtherProperties: [ : ] ,
390- isDirtyCompleted: false ,
391- updatedCompletedCount: 0 ,
392- isDirtyTotal: false ,
393- updatedTotalCount: 0 ,
394- children: Set ( ) )
346+ state = State ( fractionState: FractionState ( indeterminate: true , selfFraction: _ProgressFraction ( ) , childFraction: _ProgressFraction ( ) ) , otherProperties: [ : ] , childrenOtherProperties: [ : ] , children: Set ( ) )
395347 let result = try closure ( & values)
396348 state = values. state
397349 return result
@@ -405,7 +357,7 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
405357// var values = Values(manager: self, state: state)
406358// // This is done to avoid copy on write later
407359// state = State(fractionState: FractionState(indeterminate: true, selfFraction: _ProgressFraction(), childFraction: _ProgressFraction()), otherProperties: [:], childrenOtherProperties: [:])
408- //
360+ //
409361// do {
410362// let result = try closure(&values)
411363// state = values.state
@@ -477,26 +429,14 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
477429 let current : _ProgressFraction
478430 }
479431
480- private func getPreviousAndCurrentState( state: inout State ) -> UpdateState {
481- let prev = state. fractionState. overallFraction
482- if state. isDirtyTotal {
483- if state. updatedTotalCount == nil {
484- print ( " updated total count is nil " )
485- state. fractionState. indeterminate = true
486- } else {
487- state. fractionState. indeterminate = false
488- }
489- // actually update totalCount
490- if ( state. fractionState. selfFraction. total != ( state. updatedTotalCount ?? 0 ) ) && ( state. fractionState. selfFraction. total > 0 ) {
491- state. fractionState. childFraction = state. fractionState. childFraction * _ProgressFraction( completed: state. fractionState. selfFraction. total, total: state. updatedTotalCount ?? 1 )
492- }
493- state. fractionState. selfFraction. total = state. updatedTotalCount ?? 0
432+ private func updateCompletedCount( count: Int ) -> UpdateState {
433+ // Acquire and release child's lock
434+ let ( previous, current) = state. withLock { state in
435+ let prev = state. fractionState. overallFraction
436+ state. fractionState. selfFraction. completed += count
437+ return ( prev, state. fractionState. overallFraction)
494438 }
495- if state. isDirtyCompleted {
496- // actually update completedCount
497- state. fractionState. selfFraction. completed = state. updatedCompletedCount
498- }
499- return UpdateState ( previous: prev, current: state. fractionState. overallFraction)
439+ return UpdateState ( previous: previous, current: current)
500440 }
501441
502442 private func updateFractionCompleted( from: _ProgressFraction , to: _ProgressFraction ) {
@@ -538,60 +478,11 @@ internal struct AnyMetatypeWrapper: Hashable, Equatable, Sendable {
538478 state. fractionState. childFraction = state. fractionState. childFraction - ( multiple * next)
539479 }
540480 }
541- state. isDirtyTotal = false
542- state. isDirtyCompleted = false
543481 return UpdateState ( previous: previousOverallFraction, current: state. fractionState. overallFraction)
544482 }
545483 updateFractionCompleted ( from: updateState. previous, to: updateState. current)
546484 }
547485
548-
549- /// Update completedCount and mark all ancestors as dirty.
550- private func markCompletedDirty( state: inout State ) {
551- state. isDirtyCompleted = true
552-
553- // recursively mark all ancestors as dirty
554- parents. withLock { parents in
555- for (parent, _) in parents {
556- parent. markCompletedDirty ( )
557- }
558- }
559- }
560-
561- private func markCompletedDirty( ) {
562- state. withLock { state in
563- state. isDirtyCompleted = true
564- }
565-
566- parents. withLock { parents in
567- for (parent, _) in parents {
568- parent. markCompletedDirty ( )
569- }
570- }
571- }
572-
573- private func markTotalDirty( state: inout State ) {
574- state. isDirtyTotal = true
575-
576- parents. withLock { parents in
577- for (parent, _) in parents {
578- parent. markTotalDirty ( )
579- }
580- }
581- }
582-
583- private func markTotalDirty( ) {
584- state. withLock { state in
585- state. isDirtyTotal = true
586- }
587-
588- parents. withLock { parents in
589- for (parent, _) in parents {
590- parent. markTotalDirty ( )
591- }
592- }
593- }
594-
595486 //MARK: Interop-related internal methods
596487 /// Adds `observer` to list of `_observers` in `self`.
597488 internal func addObserver( observer: @escaping @Sendable ( ObserverState ) -> Void ) {
0 commit comments