@@ -17,7 +17,10 @@ package com.diffplug.selfie
17
17
18
18
import com.diffplug.selfie.guts.CallStack
19
19
import com.diffplug.selfie.guts.DiskStorage
20
+ import com.diffplug.selfie.guts.atomic
20
21
import com.diffplug.selfie.guts.recordCall
22
+ import com.diffplug.selfie.guts.reentrantLock
23
+ import com.diffplug.selfie.guts.withLock
21
24
22
25
private const val OPEN = " «"
23
26
private const val CLOSE = " »"
@@ -32,29 +35,34 @@ internal constructor(
32
35
private val call = recordCall(false )
33
36
fun createVcr () = VcrSelfie (sub, call, disk)
34
37
}
38
+ private val state: State
35
39
36
40
internal sealed class State {
37
41
class Read (val frames : List <Pair <String , SnapshotValue >>) : State() {
38
- var currentFrame = 0
42
+ fun currentFrameThenAdvance (): Int = cf.getAndUpdate { it + 1 }
43
+ fun framesReadSoFar (): Int = cf.get()
44
+ private val cf = atomic(0 )
39
45
}
40
46
41
47
class Write : State () {
42
- private val frames = mutableListOf<Pair <String , SnapshotValue >>()
48
+ private val lock = reentrantLock()
49
+ private var frames: MutableList <Map .Entry <String , SnapshotValue >>? =
50
+ mutableListOf<Map .Entry <String , SnapshotValue >>()
43
51
fun add (key : String , value : SnapshotValue ) {
44
- frames.add(key to value)
45
- }
46
- fun toSnapshot (): Snapshot {
47
- var snapshot = Snapshot .of(" " )
48
- var idx = 1
49
- for ((key, value) in frames) {
50
- snapshot = snapshot.plusFacet(" $OPEN$idx$CLOSE$key " , value)
51
- ++ idx
52
+ lock.withLock {
53
+ frames?.add(entry(key, value))
54
+ ? : throw IllegalStateException (" This VCR was already closed." )
52
55
}
53
- return snapshot
54
56
}
57
+ fun closeAndGetSnapshot (): Snapshot =
58
+ Snapshot .ofEntries(
59
+ lock.withLock {
60
+ val frozen = frames ? : throw IllegalStateException (" This VCR was already closed." )
61
+ frames = null
62
+ frozen
63
+ })
55
64
}
56
65
}
57
- private val state: State
58
66
59
67
init {
60
68
val canWrite = Selfie .system.mode.canWrite(isTodo = false , call, Selfie .system)
@@ -81,24 +89,25 @@ internal constructor(
81
89
}
82
90
override fun close () {
83
91
if (state is State .Read ) {
84
- if (state.frames.size != state.currentFrame ) {
92
+ if (state.frames.size != state.framesReadSoFar() ) {
85
93
throw Selfie .system.fs.assertFailed(
86
- Selfie .system.mode.msgVcrUnread(state.frames.size, state.currentFrame ))
94
+ Selfie .system.mode.msgVcrUnread(state.frames.size, state.framesReadSoFar() ))
87
95
}
88
96
} else {
89
- disk.writeDisk((state as State .Write ).toSnapshot (), sub, call)
97
+ disk.writeDisk((state as State .Write ).closeAndGetSnapshot (), sub, call)
90
98
}
91
99
}
92
100
private fun nextFrameValue (state : State .Read , key : String ): SnapshotValue {
93
101
val mode = Selfie .system.mode
94
102
val fs = Selfie .system.fs
95
- if (state.frames.size <= state.currentFrame) {
103
+ val currentFrame = state.currentFrameThenAdvance()
104
+ if (state.frames.size <= currentFrame) {
96
105
throw fs.assertFailed(mode.msgVcrUnderflow(state.frames.size))
97
106
}
98
- val expected = state.frames[state. currentFrame++ ]
107
+ val expected = state.frames[currentFrame]
99
108
if (expected.first != key) {
100
109
throw fs.assertFailed(
101
- mode.msgVcrMismatch(" $sub [$OPEN${state. currentFrame}$CLOSE ]" , expected.first, key),
110
+ mode.msgVcrMismatch(" $sub [$OPEN${currentFrame}$CLOSE ]" , expected.first, key),
102
111
expected.first,
103
112
key)
104
113
}
0 commit comments