Skip to content

Commit dbc6e7d

Browse files
committed
Make APIs more Swifty
1 parent 7ff966b commit dbc6e7d

File tree

8 files changed

+382
-297
lines changed

8 files changed

+382
-297
lines changed

Concurrent/STM.swift

Lines changed: 50 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,60 @@
88
// This file is a fairly clean port of FSharpX's implementation
99
// ~(https://github.com/fsprojects/FSharpx.Extras/)
1010

11-
11+
/// A monad supporting atomic memory transactions.
1212
public struct STM<T> {
13+
/// Perform a series of STM actions atomically.
1314
public func atomically() -> T {
1415
do {
1516
return try TLog.atomically { try self.unSTM($0) }
1617
} catch _ {
17-
fatalError()
18+
fatalError("Retry should have been caught internally.")
1819
}
1920
}
2021

22+
/// Retry execution of the current memory transaction because it has seen
23+
/// values in `TVar`s which mean that it should not continue.
24+
///
25+
/// The implementation may block the thread until one of the `TVar`s that it
26+
/// has read from has been udpated.
27+
public static func retry() -> STM<T> {
28+
return STM { trans in
29+
return try trans.retry()
30+
}
31+
}
32+
33+
/// Compose two alternative STM actions (GHC only).
34+
///
35+
/// If the first action completes without retrying then it forms the result
36+
/// of the `orElse`. Otherwise, if the first action retries, then the second
37+
/// action is tried in its place. If both actions retry then the `orElse` as
38+
/// a whole retries.
39+
public func orElse(b : STM<T>) -> STM<T> {
40+
return STM { trans in
41+
do {
42+
return try trans.orElse(self.unSTM, q: b.unSTM)
43+
} catch _ {
44+
fatalError()
45+
}
46+
}
47+
}
48+
2149
private let unSTM : TLog throws -> T
50+
51+
internal init(_ unSTM : TLog throws -> T) {
52+
self.unSTM = unSTM
53+
}
2254
}
2355

2456
extension STM /*: Functor*/ {
57+
/// Apply a function to the result of an STM transaction.
2558
public func fmap<B>(f : T -> B) -> STM<B> {
2659
return self.flatMap { x in STM<B>.pure(f(x)) }
2760
}
2861
}
2962

3063
extension STM /*: Pointed*/ {
64+
/// Lift a value into a trivial STM transaction.
3165
public static func pure<T>(x : T) -> STM<T> {
3266
return STM<T> { _ in
3367
return x
@@ -36,73 +70,38 @@ extension STM /*: Pointed*/ {
3670
}
3771

3872
extension STM /*: Applicative*/ {
73+
/// Atomically apply a function to the result of an STM transaction.
3974
public func ap<B>(fab : STM<T -> B>) -> STM<B> {
4075
return fab.flatMap(self.fmap)
4176
}
4277
}
4378

4479
extension STM /*: Monad*/ {
80+
/// Atomically apply a function to the result of an STM transaction that
81+
/// yields a continuation transaction to be executed later.
82+
///
83+
/// This function can be used to implement other atomic primitives.
4584
public func flatMap<B>(rest : T -> STM<B>) -> STM<B> {
4685
return STM<B> { trans in
4786
return try rest(try! self.unSTM(trans)).unSTM(trans)
4887
}
4988
}
5089

90+
/// Atomically execute the first action then execute the second action
91+
/// immediately after.
5192
public func then<B>(then : STM<B>) -> STM<B> {
5293
return self.flatMap { _ in
5394
return then
5495
}
5596
}
5697
}
5798

58-
public func readTVar<T>(ref : TVar<T>) -> STM<T> {
59-
return STM { trans in
60-
return trans.readTVar(ref)
61-
}
62-
}
63-
64-
public func writeTVar<T : Equatable>(ref : TVar<T>, value : T) -> STM<()> {
65-
return STM<T> { (trans : TLog) in
66-
trans.writeTVar(ref, value: PreEquatable(t: { value }))
67-
return value
68-
}.then(STM<()>.pure(()))
69-
}
70-
71-
public func writeTVar<T : AnyObject>(ref : TVar<T>, value : T) -> STM<()> {
72-
return STM<T> { (trans : TLog) in
73-
trans.writeTVar(ref, value: UnderlyingRef(t: { value }))
74-
return value
75-
}.then(STM<()>.pure(()))
76-
}
77-
78-
public func writeTVar<T : Any>(ref : TVar<T>, value : T) -> STM<()> {
79-
return STM<T> { (trans : TLog) in
80-
trans.writeTVar(ref, value: Ref(t: { value }))
81-
return value
82-
}.then(STM<()>.pure(()))
83-
}
84-
85-
public func retry<T>() throws -> STM<T> {
86-
return STM { trans in
87-
return try trans.retry()
88-
}
89-
}
90-
91-
public func orElse<T>(a : STM<T>, b : STM<T>) -> STM<T> {
92-
return STM { trans in
93-
do {
94-
return try trans.orElse(a.unSTM, q: b.unSTM)
95-
} catch _ {
96-
fatalError()
97-
}
98-
}
99-
}
100-
101-
private final class Entry<T> {
99+
internal final class Entry<T> {
102100
let oldValue : TVarType<T>
103101
var location : TVar<T>
104102
var _newValue : TVarType<T>
105103
let hasOldValue : Bool
104+
106105
var isValid : Bool {
107106
return !hasOldValue || location.value == self.oldValue
108107
}
@@ -137,6 +136,7 @@ private final class Entry<T> {
137136
self.location.value = self._newValue
138137
}
139138

139+
// HACK: bridge-all-the-things-to-Any makes this a legal transformation.
140140
var upCast : Entry<Any> {
141141
return Entry<Any>(self.oldValue.upCast, self.location.upCast, self._newValue.upCast, self.hasOldValue)
142142
}
@@ -151,12 +151,13 @@ private enum STMError : ErrorType {
151151
private var _current : Any? = nil
152152

153153
/// A transactional memory log
154-
private final class TLog {
154+
internal final class TLog {
155155
lazy var locker = UnsafeMutablePointer<pthread_mutex_t>.alloc(sizeof(pthread_mutex_t))
156156
lazy var cond = UnsafeMutablePointer<pthread_cond_t>.alloc(sizeof(pthread_mutex_t))
157157

158158
let outer : TLog?
159-
var log : Dictionary<TVar<Any>, Entry<Any>> = Dictionary()
159+
var log : Dictionary<TVar<Any>, Entry<Any>> = [:]
160+
160161
var isValid : Bool {
161162
return self.log.values.reduce(true, combine: { $0 && $1.isValid }) && (outer == nil || outer!.isValid)
162163
}
@@ -187,12 +188,12 @@ private final class TLog {
187188
}
188189
}
189190

191+
// FIXME: Replace with with an MVar.
190192
func lock() {
191193
pthread_mutex_lock(self.locker)
192194
}
193195

194196
func block() {
195-
print("Block!")
196197
guard pthread_mutex_trylock(self.locker) != 0 else {
197198
fatalError("thread must be locked in order to wait")
198199
}

Concurrent/TBQueue.swift

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,37 +26,33 @@ public struct TBQueue<A> {
2626
let wsize = TVar(n)
2727
self.init(rsize, read, wsize, write)
2828
}
29-
}
30-
31-
public func newTBQueue<A>(n : Int) -> STM<TBQueue<A>> {
32-
let read = TVar([] as [A])
33-
let write = TVar([] as [A])
34-
let rsize = TVar(0)
35-
let wsize = TVar(n)
36-
return STM<TBQueue<A>>.pure(TBQueue(rsize, read, wsize, write))
37-
}
38-
39-
public func writeTBQueue<A>(q : TBQueue<A>, _ x : A) -> STM<()> {
40-
return readTVar(q.writeNum).flatMap { w in
41-
let act : STM<()>
42-
if w != 0 {
43-
act = writeTVar(q.writeNum, value: w - 1)
44-
} else {
45-
act = readTVar(q.readNum).flatMap { r in
46-
if r != 0 {
47-
return writeTVar(q.readNum, value: 0).then(writeTVar(q.writeNum, value: r - 1))
48-
} else {
49-
do {
50-
return try retry()
51-
} catch _ {
52-
fatalError()
29+
30+
public static func create(n : Int) -> STM<TBQueue<A>> {
31+
let read = TVar([] as [A])
32+
let write = TVar([] as [A])
33+
let rsize = TVar(0)
34+
let wsize = TVar(n)
35+
return STM<TBQueue<A>>.pure(TBQueue(rsize, read, wsize, write))
36+
}
37+
38+
public func write(x : A) -> STM<()> {
39+
return self.writeNum.read().flatMap { w in
40+
let act : STM<()>
41+
if w != 0 {
42+
act = self.writeNum.write(w - 1)
43+
} else {
44+
act = self.readNum.read().flatMap { r in
45+
if r != 0 {
46+
return self.readNum.write(0).then(self.writeNum.write(r - 1))
47+
} else {
48+
return STM.retry()
5349
}
5450
}
5551
}
52+
53+
return act.then(self.writeHead.read().flatMap { listend in
54+
return self.writeHead.write([x] + listend)
55+
})
5656
}
57-
58-
return act.then(readTVar(q.writeHead).flatMap { listend in
59-
return writeTVar(q.writeHead, value: [x] + listend)
60-
})
6157
}
62-
}
58+
}

0 commit comments

Comments
 (0)