6
6
// Copyright © 2015 TypeLift. All rights reserved.
7
7
//
8
8
9
+ /// `TBQueue` is a bounded version of `TQueue`. The queue has a maximum capacity
10
+ /// set when it is created. If the queue already contains the maximum number of
11
+ /// elements, then `write()` blocks until an element is removed from the queue.
9
12
public struct TBQueue < A> {
10
13
let readNum : TVar < Int >
11
14
let readHead : TVar < [ A ] >
@@ -19,22 +22,27 @@ public struct TBQueue<A> {
19
22
self . writeHead = writeHead
20
23
}
21
24
25
+ /// Creates and initializes a new `TBQueue`.
22
26
public init ( n : Int ) {
23
27
let read = TVar ( [ A] ( ) )
24
28
let write = TVar ( [ A] ( ) )
25
29
let rsize = TVar ( 0 )
26
30
let wsize = TVar ( n)
27
31
self . init ( rsize, read, wsize, write)
28
32
}
29
-
33
+
34
+ /// Uses an atomic transaction to create and initialize a new `TBQueue`.
30
35
public static func create( n : Int ) -> STM < TBQueue < A > > {
31
36
let read = TVar ( [ ] as [ A ] )
32
37
let write = TVar ( [ ] as [ A ] )
33
38
let rsize = TVar ( 0 )
34
39
let wsize = TVar ( n)
35
40
return STM< TBQueue< A>>. pure( TBQueue ( rsize, read, wsize, write) )
36
41
}
37
-
42
+
43
+ /// Uses an atomic transaction to write the given value to the receiver.
44
+ ///
45
+ /// Blocks if the queue is full.
38
46
public func write( x : A ) -> STM < ( ) > {
39
47
return self . writeNum. read ( ) . flatMap { w in
40
48
let act : STM < ( ) >
@@ -55,4 +63,100 @@ public struct TBQueue<A> {
55
63
} )
56
64
}
57
65
}
66
+
67
+ /// Uses an atomic transaction to read the next value from the receiver.
68
+ public func read( ) -> STM < A > {
69
+ return self . readHead. read ( ) . flatMap { xs in
70
+ return self . readNum. read ( ) . flatMap { r in
71
+ return self . readNum. write ( r + 1 )
72
+ . then ( {
73
+ if let x = xs. first {
74
+ return self . readHead. write ( Array ( xs. dropFirst ( ) ) ) . then ( STM< A> . pure( x) )
75
+ }
76
+ return self . writeHead. read ( ) . flatMap { ys in
77
+ if ys. isEmpty {
78
+ return STM< A> . retry( )
79
+ }
80
+ let zs = ys. reverse ( )
81
+ return self . writeHead. write ( [ ] )
82
+ . then ( self . readHead. write ( Array ( zs. dropFirst ( ) ) ) )
83
+ . then ( STM< A> . pure( ys. first!) )
84
+ }
85
+ } ( ) )
86
+ }
87
+ }
88
+ }
89
+
90
+ /// Uses an atomic transaction to read the next value from the receiver
91
+ /// without blocking or retrying on failure.
92
+ public func tryRead( ) -> STM < Optional < A > > {
93
+ return self . read ( ) . fmap ( Optional . Some) . orElse ( STM< A?> . pure( . None) )
94
+ }
95
+
96
+ /// Uses an atomic transaction to get the next value from the receiver
97
+ /// without removing it, retrying if the queue is empty.
98
+ public func peek( ) -> STM < A > {
99
+ return self . read ( ) . flatMap { x in
100
+ return self . unGet ( x) . then ( STM< A> . pure( x) )
101
+ }
102
+ }
103
+
104
+ /// Uses an atomic transaction to get the next value from the receiver
105
+ /// without removing it without retrying if the queue is empty.
106
+ public func tryPeek( ) -> STM < Optional < A > > {
107
+ return self . tryRead ( ) . flatMap { m in
108
+ switch m {
109
+ case let . Some( x) :
110
+ return self . unGet ( x) . then ( STM< A?> . pure( m) )
111
+ case . None:
112
+ return STM< A?> . pure( . None)
113
+ }
114
+ }
115
+ }
116
+
117
+ /// Uses an atomic transaction to put a data item back onto a channel where
118
+ /// it will be the next item read.
119
+ ///
120
+ /// Blocks if the queue is full.
121
+ public func unGet( x : A ) -> STM < ( ) > {
122
+ return self . readNum. read ( ) . flatMap { r in
123
+ return { ( ) -> STM < ( ) > in
124
+ if r > 0 {
125
+ return self . readNum. write ( r. predecessor ( ) )
126
+ }
127
+ return self . writeNum. read ( ) . flatMap { w in
128
+ if w > 0 {
129
+ return self . writeNum. write ( w. predecessor ( ) )
130
+ }
131
+ return STM < ( ) > . retry ( )
132
+ }
133
+ } ( ) . then ( self . readHead. read ( ) . flatMap { xs in
134
+ return self . readHead. write ( [ x] + xs)
135
+ } )
136
+ }
137
+ }
138
+
139
+ /// Uses an STM transaction to return whether the channel is empty.
140
+ public var isEmpty : STM < Bool > {
141
+ return self . readHead. read ( ) . flatMap { xs in
142
+ if xs. isEmpty {
143
+ return self . writeHead. read ( ) . flatMap { ys in
144
+ return STM< Bool> . pure( ys. isEmpty)
145
+ }
146
+ }
147
+ return STM< Bool> . pure( false )
148
+ }
149
+ }
150
+
151
+ /// Uses an STM transaction to return whether the channel is full.
152
+ public var isFull : STM < Bool > {
153
+ return self . writeNum. read ( ) . flatMap { w in
154
+ if w > 0 {
155
+ return STM< Bool> . pure( false )
156
+ }
157
+ return self . readNum. read ( ) . flatMap { r in
158
+ return STM< Bool> . pure( r <= 0 )
159
+ }
160
+ }
161
+ }
58
162
}
0 commit comments