Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Feb 2, 2025. It is now read-only.

Commitc038275

Browse files
author
Alex Belozierov
committed
- improved CoScope performance
- fixed bugs
1 parente0d1d60 commitc038275

File tree

67 files changed

+855
-254
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+855
-254
lines changed

‎._SwiftCoroutine.xcodeproj‎

4 KB
Binary file not shown.

‎README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ DispatchQueue.main.startCoroutine {
7474
###Requirements
7575

7676
- iOS 10+ / macOS 10.12+ / Ubuntu
77-
- Xcode 10.2+
78-
- Swift 5+
77+
- Xcode 10.4+
78+
- Swift 5.2+
7979

8080
###Installation
8181

‎Sources/SwiftCoroutine/CoChannel/CoChannel.swift‎

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public final class CoChannel<Element> {
3838
publicletmaxBufferSize:Int
3939
privatevarreceiveCallbacks=FifoQueue<ReceiveCallback>()
4040
privatevarsendBlocks=FifoQueue<SendBlock>()
41-
privatevarcancelBlocks=CallbackStack<Void>()
41+
privatevarcompleteBlocks=CallbackStack<CoChannelError?>()
4242
privatevaratomic=AtomicTuple()
4343

4444
/// Initializes a channel.
@@ -255,14 +255,34 @@ public final class CoChannel<Element> {
255255
atomic.value.1==2
256256
}
257257

258+
/// Adds an observer callback that is called when the `CoChannel` is canceled.
259+
/// - Parameter callback: The callback that is called when the `CoChannel` is canceled.
260+
publicfunc whenCanceled(_ callback:@escaping()->Void){
261+
whenFinished{if $0==.canceled{callback()}}
262+
}
263+
264+
// MARK: - complete
265+
258266
/// Adds an observer callback that is called when the `CoChannel` is completed (closed, canceled or deinited).
259267
/// - Parameter callback: The callback that is called when the `CoChannel` is completed.
260268
publicfunc whenComplete(_ callback:@escaping()->Void){
261-
if !cancelBlocks.append(callback){callback()}
269+
whenFinished{ _incallback()}
270+
}
271+
272+
privatefunc whenFinished(_ callback:@escaping(CoChannelError?)->Void){
273+
if !completeBlocks.append(callback){callback(channelError)}
262274
}
263275

264276
privatefunc finish(){
265-
cancelBlocks.close()?.finish(with:())
277+
completeBlocks.close()?.finish(with: channelError)
278+
}
279+
280+
privatevarchannelError:CoChannelError?{
281+
switch atomic.value.1{
282+
case1:return.closed
283+
case2:return.canceled
284+
default:returnnil
285+
}
266286
}
267287

268288
deinit{

‎Sources/SwiftCoroutine/CoChannel/CoChannel1+Receiver.swift‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ extension CoChannel {
6767
/// Returns `true` if the channel is canceled.
6868
publicvarisCanceled:Bool{true}
6969

70+
/// Adds an observer callback that is called when the `CoChannel` is canceled.
71+
/// - Parameter callback: The callback that is called when the `CoChannel` is canceled.
72+
publicfunc whenCanceled(_ callback:@escaping()->Void){
73+
callback()
74+
}
75+
76+
// MARK: - complete
77+
7078
/// Adds an observer callback that is called when the `CoChannel` is completed (closed, canceled or deinited).
7179
/// - Parameter callback: The callback that is called when the `CoChannel` is completed.
7280
publicfunc whenComplete(_ callback:@escaping()->Void){

‎Sources/SwiftCoroutine/CoChannel/CoChannel2+Sender.swift‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ extension CoChannel.Sender {
8686
channel.isCanceled
8787
}
8888

89+
/// Adds an observer callback that is called when the `CoChannel` is canceled.
90+
/// - Parameter callback: The callback that is called when the `CoChannel` is canceled.
91+
publicfunc whenCanceled(_ callback:@escaping()->Void){
92+
channel.whenCanceled(callback)
93+
}
94+
95+
// MARK: - complete
96+
8997
/// Adds an observer callback that is called when the `CoChannel` is completed (closed, canceled or deinited).
9098
/// - Parameter callback: The callback that is called when the `CoChannel` is completed.
9199
@inlinablepublicfunc whenComplete(_ callback:@escaping()->Void){

‎Sources/SwiftCoroutine/CoChannel/Receive/CoChannelReceiver.swift‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,8 @@ internal final class CoChannelReceiver<T>: CoChannel<T>.Receiver {
5858
channel.whenComplete(callback)
5959
}
6060

61+
internaloverridefunc whenCanceled(_ callback:@escaping()->Void){
62+
channel.whenCanceled(callback)
63+
}
64+
6165
}

‎Sources/SwiftCoroutine/CoChannel/Receive/CoChannelReceiverProtocol.swift‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ internal protocol CoChannelReceiverProtocol {
1919
func cancel()
2020
varisCanceled:Bool{get}
2121
func whenComplete(_ callback:@escaping()->Void)
22+
func whenCanceled(_ callback:@escaping()->Void)
2223
varmaxBufferSize:Int{get}
2324

2425
}

‎Sources/SwiftCoroutine/CoScope/CoScope.swift‎

Lines changed: 26 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -36,121 +36,63 @@
3636
///
3737
publicfinalclassCoScope{
3838

39-
privatetypealiasBlock=()->Void
40-
41-
privatevaritems=[Int: Block]()
42-
privatevarcallbacks=[Block]()
43-
privatevarstate=Int.free
44-
privatevarkeyCounter=0
39+
internaltypealiasCompletion=()->Void
40+
privatevarstorage=Storage<Completion>()
41+
privatevarcallbacks=CallbackStack<Void>()
4542

4643
/// Initializes a scope.
4744
publicinit(){}
4845

4946
/// Adds weak referance of `CoCancellable` to be canceled when the scope is being canceled or deinited.
5047
/// - Parameter item: `CoCancellable` to add.
51-
@inlinablepublicfunc add(_ item:CoCancellable){
52-
item.whenComplete(add{[weak item]in item?.cancel()})
53-
}
54-
55-
@usableFromInlineinternalfunc add(_ cancel:@escaping()->Void)->()->Void{
56-
letkey=atomicAdd(&keyCounter, value:1)
57-
addItem(for: key, block: cancel)
58-
return{[weak self]inself?.removeItem(for: key)}
59-
}
60-
61-
/// Returns `true` if the scope is empty (contains no `CoCancellable`).
62-
publicvarisEmpty:Bool{
63-
if isCanceled{returntrue}
64-
varisEmpty=true
65-
locked{ isEmpty= items.isEmpty}
66-
return isEmpty
67-
}
68-
69-
// MARK: - items
70-
71-
privatefunc addItem(for key:Int, block:@escapingBlock){
72-
if !locked({items[key]= block}){block()}
48+
publicfunc add(_ item:CoCancellable){
49+
add{[weak item]in item?.cancel()}.map(item.whenComplete)
7350
}
7451

75-
privatefunc removeItem(for key:Int){
76-
locked{items[key]=nil}
52+
internalfunc add(_ cancel:@escaping()->Void)->Completion?{
53+
if isCanceled{cancel();returnnil}
54+
letkey= storage.append(cancel)
55+
if isCanceled{ storage.remove(key)?();returnnil}
56+
return{[weak self]inself?.remove(key: key)}
7757
}
7858

79-
// MARK: - lock
80-
81-
@discardableResultprivatefunc locked(_ block:Block)->Bool{
82-
whiletrue{
83-
switch state{
84-
case.free:
85-
ifatomicCAS(&state, expected:.free, desired:.busy){
86-
block()
87-
unlock()
88-
returntrue
89-
}
90-
case.busy:
91-
continue
92-
default:
93-
returnfalse
94-
}
95-
}
59+
privatefunc remove(key:Storage<Completion>.Index){
60+
storage.remove(key)
9661
}
9762

98-
privatefunc unlock(){
99-
whiletrue{
100-
switch state{
101-
case.busy:
102-
ifatomicCAS(&state, expected:.busy, desired:.free){return}
103-
default:
104-
returncompleteAll()
105-
}
106-
}
63+
/// Returns `true` if the scope is empty (contains no `CoCancellable`).
64+
publicvarisEmpty:Bool{
65+
isCanceled || storage.isEmpty
10766
}
10867

10968
// MARK: - cancel
11069

11170
/// Returns `true` if the scope is canceled.
11271
publicvarisCanceled:Bool{
113-
state==.canceled
72+
callbacks.isClosed
11473
}
11574

11675
/// Cancels the scope and all `CoCancellable` that it contains.
11776
publicfunc cancel(){
118-
whiletrue{
119-
switch state{
120-
case.free:
121-
if !atomicCAS(&state, expected:.free, desired:.canceled){continue}
122-
returncompleteAll()
123-
case.busy:
124-
ifatomicCAS(&state, expected:.busy, desired:.canceled){return}
125-
default:
126-
return
127-
}
128-
}
77+
if isCanceled{return}
78+
completeAll()
79+
storage.removeAll()
80+
}
81+
82+
privatefunc completeAll(){
83+
callbacks.close()?.finish(with:())
84+
storage.forEach{$0()}
12985
}
13086

13187
/// Adds an observer callback that is called when the `CoScope` is canceled or deinited.
13288
/// - Parameter callback: The callback that is called when the scope is canceled or deinited.
13389
publicfunc whenComplete(_ callback:@escaping()->Void){
134-
if !locked({ callbacks.append(callback)}){callback()}
135-
}
136-
137-
privatefunc completeAll(){
138-
items.values.forEach{$0()}
139-
items.removeAll()
140-
callbacks.forEach{$0()}
141-
callbacks.removeAll()
90+
if !callbacks.append(callback){callback()}
14291
}
14392

14493
deinit{
14594
if !isCanceled{completeAll()}
95+
storage.free()
14696
}
14797

14898
}
149-
150-
fileprivateextensionInt{
151-
152-
staticletcanceled=-1
153-
staticletfree=0
154-
staticletbusy=1
155-
156-
}

‎Sources/SwiftCoroutine/Coroutine/TaskScheduler/CoroutineScheduler.swift‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ extension CoroutineScheduler {
6868
publicfunc startCoroutine(in scope:CoScope?=nil, task:@escaping()throws->Void){
6969
guardlet scope= scopeelse{return_startCoroutine{try?task()}}
7070
_startCoroutine{
71-
letcoroutine=try?Coroutine.current()
72-
letfinish= scope.add{[weakcoroutine]in coroutine?.cancel()}
73-
if !scope.isCanceled{try?task()}
74-
finish()
71+
guardlet coroutine=try?Coroutine.current(),
72+
letcompletion= scope.add(coroutine.cancel)else{return}
73+
try?task()
74+
completion()
7575
}
7676
}
7777

@@ -113,8 +113,9 @@ extension CoroutineScheduler {
113113
@inlinablepublicfunc coroutineFuture<T>(_ task:@escaping()throws->T)->CoFuture<T>{
114114
letpromise=CoPromise<T>()
115115
_startCoroutine{
116-
letcurrent=try?Coroutine.current()
117-
promise.whenCanceled{ current?.cancel()}
116+
iflet coroutine=try?Coroutine.current(){
117+
promise.whenCanceled(coroutine.cancel)
118+
}
118119
if promise.isCanceled{return}
119120
promise.complete(with:Result(catching: task))
120121
}
@@ -165,8 +166,9 @@ extension CoroutineScheduler {
165166
@inlinablepublicfuncactor<T>(of type:T.Type=T.self, maxBufferSize:Int=.max, body:@escaping(CoChannel<T>.Receiver)throws->Void)->CoChannel<T>.Sender{
166167
let(receiver, sender)=CoChannel<T>(maxBufferSize: maxBufferSize).pair
167168
_startCoroutine{
168-
letcoroutine=try?Coroutine.current()
169-
receiver.whenComplete{ coroutine?.cancel()}
169+
iflet coroutine=try?Coroutine.current(){
170+
receiver.whenCanceled{[weak coroutine]in coroutine?.cancel()}
171+
}
170172
if receiver.isCanceled{return}
171173
try?body(receiver)
172174
}
4 KB
Binary file not shown.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp