Skip to content

Commit 03a0fc9

Browse files
authored
Merge pull request #46 from CodaFi/pchan-tchan
Introduce laziness into TChan and ditch custom list
2 parents 82b6bfe + 7298d82 commit 03a0fc9

File tree

13 files changed

+134
-120
lines changed

13 files changed

+134
-120
lines changed

.travis.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ matrix:
55
include:
66
- os: osx
77
language: objective-c
8-
osx_image: xcode8
8+
osx_image: xcode8.3
99
before_install:
1010
- git submodule update --init --recursive
1111
script:
@@ -14,7 +14,7 @@ matrix:
1414
- carthage build --no-skip-current
1515
- os: osx
1616
language: objective-c
17-
osx_image: xcode8
17+
osx_image: xcode8.3
1818
before_install:
1919
- git submodule update --init --recursive
2020
script:
@@ -37,9 +37,9 @@ matrix:
3737
before_install:
3838
- git submodule update --init --recursive
3939
- wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
40-
- wget https://swift.org/builds/swift-3.0-release/ubuntu1404/swift-3.0-RELEASE/swift-3.0-RELEASE-ubuntu14.04.tar.gz
41-
- tar xzf swift-3.0-RELEASE-ubuntu14.04.tar.gz
42-
- export PATH=${PWD}/swift-3.0-RELEASE-ubuntu14.04/usr/bin:"${PATH}"
40+
- wget https://swift.org/builds/swift-3.1-release/ubuntu1404/swift-3.1-RELEASE/swift-3.1-RELEASE-ubuntu14.04.tar.gz
41+
- tar xzf swift-3.1-RELEASE-ubuntu14.04.tar.gz
42+
- export PATH=${PWD}/swift-3.1-RELEASE-ubuntu14.04/usr/bin:"${PATH}"
4343
script:
4444
- swift build
4545
notifications:

Cartfile.resolved

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
github "typelift/SwiftCheck" "v0.7.0"
1+
github "typelift/SwiftCheck" "0.8.0"

Carthage/Checkouts/SwiftCheck

Submodule SwiftCheck updated 54 files

Concurrent.xcodeproj/project.pbxproj

Lines changed: 67 additions & 67 deletions
Large diffs are not rendered by default.

Sources/TChan.swift

Lines changed: 60 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,21 @@
66
// Copyright © 2015-2016 TypeLift. All rights reserved.
77
//
88

9-
private indirect enum TList<A> {
10-
case tNil
11-
case tCons(A, TVar<TList<A>>)
12-
}
13-
149
/// Transactional Channels are unbounded FIFO streams of values with a read and
1510
/// write terminals comprised of `TVar`s.
1611
public struct TChan<A> {
17-
private let readHead : TVar<TVar<TList<A>>>
18-
private let writeHead : TVar<TVar<TList<A>>>
12+
private let readHead : TVar<() -> TVar<[A]>>
13+
private let writeHead : TVar<TVar<[A]>>
1914

20-
private init(_ readHead : TVar<TVar<TList<A>>>, _ writeHead : TVar<TVar<TList<A>>>) {
15+
private init(_ readHead : TVar<() -> TVar<[A]>>, _ writeHead : TVar<TVar<[A]>>) {
2116
self.readHead = readHead
2217
self.writeHead = writeHead
2318
}
2419

2520
/// Creates and returns a new empty channel.
2621
public init() {
27-
let hole : TVar<TList<A>> = TVar(TList.tNil)
28-
let read = TVar(hole)
22+
let hole : TVar<[A]> = TVar([])
23+
let read = TVar({ hole })
2924
let write = TVar(hole)
3025
self = TChan(read, write)
3126
}
@@ -34,16 +29,16 @@ public struct TChan<A> {
3429
///
3530
/// To read from a broadcast transactional channel, `duplicate()` it first.
3631
public init(forBroadcast: ()) {
37-
let hole : TVar<TList<A>> = TVar(TList.tNil)
38-
let read : TVar<TVar<TList<A>>> = TVar(undefined())
32+
let hole : TVar<[A]> = TVar([])
33+
let read : TVar<() -> TVar<[A]>> = TVar({ undefined("reading from a TChan created by TChan.init(forBroadcast:); use duplicate() first") })
3934
let write = TVar(hole)
4035
self = TChan(read, write)
4136
}
4237

4338
/// Uses an STM transaction to atomically create and return a new empty channel.
4439
public func newTChan() -> STM<TChan<A>> {
45-
let hole : TVar<TList<A>> = TVar(TList.tNil)
46-
let read = TVar(hole)
40+
let hole : TVar<[A]> = TVar([])
41+
let read = TVar({ hole })
4742
let write = TVar(hole)
4843
return STM<TChan<A>>.pure(TChan(read, write))
4944
}
@@ -52,29 +47,29 @@ public struct TChan<A> {
5247
///
5348
/// To read from a broadcast transactional channel, `duplicate()` it first.
5449
public func newBroadcastTChan() -> STM<TChan<A>> {
55-
let hole : TVar<TList<A>> = TVar(TList.tNil)
56-
let read : TVar<TVar<TList<A>>> = TVar(undefined())
50+
let hole : TVar<[A]> = TVar([])
51+
let read : TVar<() -> TVar<[A]>> = TVar({ undefined("reading from a TChan created by newBroadcastTChan(); use duplicate() first") })
5752
let write = TVar(hole)
5853
return STM<TChan<A>>.pure(TChan(read, write))
5954
}
6055

6156
/// Uses an STM transaction to atomically write a value to a channel.
6257
public func write(_ val : A) -> STM<()> {
6358
return self.writeHead.read().flatMap { l in
64-
let nl : TVar<TList<A>> = TVar(TList.tNil)
65-
return l.write(TList.tCons(val, nl)).then(self.writeHead.write(nl))
59+
let nl : TVar<[A]> = TVar([])
60+
return l.write([val]).then(self.writeHead.write(nl))
6661
}
6762
}
6863

6964
/// Uses an STM transaction to atomically read a value from the channel.
7065
public func read() -> STM<A> {
7166
return self.readHead.read().flatMap { hd in
72-
return hd.read().flatMap { lst in
73-
switch lst {
74-
case .tNil:
67+
return hd().read().flatMap { lst in
68+
switch lst.match {
69+
case .Nil:
7570
return STM.retry()
76-
case .tCons(let x, let xs):
77-
return self.readHead.write(xs).then(STM<A>.pure(x))
71+
case .Cons(let x, let xs):
72+
return self.readHead.write({ TVar(xs) }).then(STM<A>.pure(x))
7873
}
7974
}
8075
}
@@ -84,12 +79,12 @@ public struct TChan<A> {
8479
/// without retrying on failure.
8580
public func tryRead() -> STM<Optional<A>> {
8681
return self.readHead.read().flatMap { hd in
87-
return hd.read().flatMap { lst in
88-
switch lst {
89-
case .tNil:
82+
return hd().read().flatMap { lst in
83+
switch lst.match {
84+
case .Nil:
9085
return STM<Optional<A>>.pure(nil)
91-
case .tCons(let x, let xs):
92-
return self.readHead.write(xs).then(STM<Optional<A>>.pure(.some(x)))
86+
case .Cons(let x, let xs):
87+
return self.readHead.write({ TVar(xs) }).then(STM<Optional<A>>.pure(.some(x)))
9388
}
9489
}
9590
}
@@ -99,11 +94,11 @@ public struct TChan<A> {
9994
/// channel, retrying on failure.
10095
public func peek() -> STM<A> {
10196
return self.readHead.read().flatMap { hd in
102-
return hd.read().flatMap { lst in
103-
switch lst {
104-
case .tNil:
97+
return hd().read().flatMap { lst in
98+
switch lst.match {
99+
case .Nil:
105100
return STM.retry()
106-
case .tCons(let x, _):
101+
case .Cons(let x, _):
107102
return STM<A>.pure(x)
108103
}
109104
}
@@ -114,11 +109,11 @@ public struct TChan<A> {
114109
/// channel without retrying.
115110
public func tryPeek() -> STM<Optional<A>> {
116111
return self.readHead.read().flatMap { hd in
117-
return hd.read().flatMap { lst in
118-
switch lst {
119-
case .tNil:
112+
return hd().read().flatMap { lst in
113+
switch lst.match {
114+
case .Nil:
120115
return STM<Optional<A>>.pure(.none)
121-
case .tCons(let x, _):
116+
case .Cons(let x, _):
122117
return STM<Optional<A>>.pure(.some(x))
123118
}
124119
}
@@ -132,28 +127,29 @@ public struct TChan<A> {
132127
/// broadcast channel, where data written by anyone is seen by everyone else.
133128
public func duplicate() -> STM<TChan<A>> {
134129
return self.writeHead.read().flatMap { hd in
135-
let newread = TVar(hd)
136-
return STM<TChan<A>>.pure(TChan(newread, self.writeHead))
130+
let newread = TVar({ hd })
131+
return STM<TChan<A>>.pure(TChan(newread, self.writeHead))
137132
}
138133
}
139134

140135
/// Uses an STM transaction to atomically put a data item back onto a
141136
/// channel, where it will be the next item read.
142137
public func unGet(_ x : A) -> STM<()> {
143138
return self.readHead.read().flatMap { hd in
144-
let newhd = TVar(TList.tCons(x, hd))
145-
return self.readHead.write(newhd)
139+
return hd().read().flatMap { head in
140+
return self.readHead.write({ TVar([x] + head) })
141+
}
146142
}
147143
}
148144

149145
/// Uses an STM transaction to return whether the channel is empty.
150146
public var isEmpty : STM<Bool> {
151147
return self.readHead.read().flatMap { hd in
152-
return hd.read().flatMap { lst in
153-
switch lst {
154-
case .tNil:
148+
return hd().read().flatMap { lst in
149+
switch lst.match {
150+
case .Nil:
155151
return STM<Bool>.pure(true)
156-
case .tCons(_, _):
152+
case .Cons(_, _):
157153
return STM<Bool>.pure(false)
158154
}
159155
}
@@ -172,6 +168,24 @@ public struct TChan<A> {
172168
}
173169
}
174170

175-
private func undefined<A>() -> A {
176-
fatalError("")
171+
private func undefined<A>(_ msg : String) -> A {
172+
fatalError(msg)
173+
}
174+
175+
extension Array {
176+
fileprivate var match : ArrayMatcher<Element> {
177+
if self.count == 0 {
178+
return .Nil
179+
} else if self.count == 1 {
180+
return .Cons(self[0], [])
181+
}
182+
let hd = self[0]
183+
let tl = Array(self[1..<self.count])
184+
return .Cons(hd, tl)
185+
}
186+
}
187+
188+
private enum ArrayMatcher<A> {
189+
case Nil
190+
case Cons(A, [A])
177191
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)