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.
1212public 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
2456extension 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
3063extension 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
3872extension 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
4479extension 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 {
151151private 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 }
0 commit comments