forked from hylo-lang/hylo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLazy.swift
97 lines (83 loc) · 2.93 KB
/
Lazy.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/// A lazily computed value.
///
/// The value is not computed unless accessed and is computed no more than once no matter how many
/// times it is copied or accessed.
public struct Lazy<T> {
/// The hidden state of an instance.
enum State {
/// The value has never been read; the payload is the value computation.
case unevaluated(() -> T)
/// The value has been read and is stored in the payload.
case result(T)
}
/// The hidden state of an instance.
private let state: SharedMutable<State>
/// Creates an instance whose value is `computeValue()`.
///
/// - Requires: `computeValue` does not mutate any existing state.
/// - Warning: Swift silently creates mutable captures in closures! If `computeValue` mutates
/// anything other than its local variables, you can create data races and undefined behavior.
public init(_ computeValue: @escaping () -> T) {
state = .init(.unevaluated(computeValue))
}
/// The (lazily) computed value.
public subscript() -> T {
return state.modify { s in
switch s {
case .result(let r): return r
case .unevaluated(let f):
let r = f()
s = .result(r)
return r
}
}
}
}
/// A lazily computed value whose computation might throw.
///
/// The actual value is not computed unless accessed and is computed no more than once no matter how
/// many times this value is copied or accessed. If the value computation throws, each access to
/// this value (or copy of it) throws the same error as the original access.
public struct LazyThrowing<T> {
/// The hidden state of an instance.
private enum State {
/// The value has never been read; the payload is the value computation.
case unevaluated(() throws -> T)
/// The value has been read and is stored in the payload.
case success(T)
/// An error was thrown from value computation and is stored in the payload.
case failure(any Error)
}
/// The hidden state of an instance.
private let state: SharedMutable<State>
/// Creates an instance whose value is `computeValue()`.
///
/// - Requires: `computeValue` does not mutate any existing state.
/// - Warning: Swift silently creates mutable captures in closures! If `computeValue` mutates
/// anything other than its local variables, you can create data races and undefined behavior.
public init(_ computeValue: @escaping () throws -> T) {
state = .init(.unevaluated(computeValue))
}
/// The (lazily) computed value.
///
/// - Throws the error thrown by the computation if any.
public subscript() -> T {
get throws {
return try state.modify { s in
switch s {
case .success(let r): return r
case .failure(let e): throw e
case .unevaluated(let f):
do {
let r = try f()
s = .success(r)
return r
} catch let e {
s = .failure(e)
throw e
}
}
}
}
}
}