@@ -23,6 +23,47 @@ package kotlinx.io
23
23
import kotlin.jvm.JvmField
24
24
import kotlin.jvm.JvmSynthetic
25
25
26
+ /* *
27
+ * Tracks shared segment copies.
28
+ *
29
+ * A new [SegmentCopyTracker] instance should be not shared by default (i.e. `shared == false`).
30
+ * Any further [addCopy] calls should move the tracker to a shared state (i.e. `shared == true`).
31
+ * Once a shared segment copy is recycled, [removeCopy] should be called.
32
+ * Depending on implementation, calling [removeCopy] the same number of times as [addCopy] may
33
+ * or may not transition the tracked back to unshared stated.
34
+ *
35
+ * The class is not intended for public use and currently designed to fit the only use case - within JVM SegmentPool
36
+ * implementation.
37
+ */
38
+ internal abstract class SegmentCopyTracker {
39
+ /* *
40
+ * `true` if a tracker shared by multiple segment copies.
41
+ */
42
+ abstract val shared: Boolean
43
+
44
+ /* *
45
+ * Track a new copy created by sharing an associated segment.
46
+ */
47
+ abstract fun addCopy ()
48
+
49
+ /* *
50
+ * Records reclamation of a shared segment copy associated with this tracker.
51
+ * If a tracker was in unshared state, this call should not affect an internal state.
52
+ *
53
+ * @return `true` if the segment was not shared *before* this called.
54
+ */
55
+ abstract fun removeCopy (): Boolean
56
+ }
57
+
58
+ /* *
59
+ * Simple [SegmentCopyTracker] that always reports shared state.
60
+ */
61
+ internal object AlwaysSharedCopyTracker : SegmentCopyTracker() {
62
+ override val shared: Boolean = true
63
+ override fun addCopy () = Unit
64
+ override fun removeCopy (): Boolean = true
65
+ }
66
+
26
67
/* *
27
68
* A segment of a buffer.
28
69
*
@@ -59,8 +100,17 @@ public class Segment {
59
100
internal var limit: Int = 0
60
101
61
102
/* * True if other segments or byte strings use the same byte array. */
62
- @JvmField
63
- internal var shared: Boolean = false
103
+ internal val shared: Boolean
104
+ get() = copyTracker?.shared ? : false
105
+
106
+ /* *
107
+ * Tracks number shared copies
108
+ *
109
+ * Note that this reference is not `@Volatile` as segments are not thread-safe and it's an error
110
+ * to modify the same segment concurrently.
111
+ * At the same time, an object [copyTracker] refers to could be modified concurrently.
112
+ */
113
+ internal var copyTracker: SegmentCopyTracker ? = null
64
114
65
115
/* * True if this segment owns the byte array and can append to it, extending `limit`. */
66
116
@JvmField
@@ -81,14 +131,14 @@ public class Segment {
81
131
private constructor () {
82
132
this .data = ByteArray (SIZE )
83
133
this .owner = true
84
- this .shared = false
134
+ this .copyTracker = null
85
135
}
86
136
87
- private constructor (data: ByteArray , pos: Int , limit: Int , shared : Boolean , owner: Boolean ) {
137
+ private constructor (data: ByteArray , pos: Int , limit: Int , shareToken : SegmentCopyTracker ? , owner: Boolean ) {
88
138
this .data = data
89
139
this .pos = pos
90
140
this .limit = limit
91
- this .shared = shared
141
+ this .copyTracker = shareToken
92
142
this .owner = owner
93
143
}
94
144
@@ -98,8 +148,10 @@ public class Segment {
98
148
* prevents it from being pooled.
99
149
*/
100
150
internal fun sharedCopy (): Segment {
101
- shared = true
102
- return Segment (data, pos, limit, true , false )
151
+ val t = copyTracker ? : SegmentPool .tracker().also {
152
+ copyTracker = it
153
+ }
154
+ return Segment (data, pos, limit, t.also { it.addCopy() }, false )
103
155
}
104
156
105
157
/* *
@@ -284,8 +336,13 @@ public class Segment {
284
336
internal fun new (): Segment = Segment ()
285
337
286
338
@JvmSynthetic
287
- internal fun new (data : ByteArray , pos : Int , limit : Int , shared : Boolean , owner : Boolean ): Segment
288
- = Segment (data, pos, limit, shared, owner)
339
+ internal fun new (
340
+ data : ByteArray ,
341
+ pos : Int ,
342
+ limit : Int ,
343
+ copyTracker : SegmentCopyTracker ? ,
344
+ owner : Boolean
345
+ ): Segment = Segment (data, pos, limit, copyTracker, owner)
289
346
}
290
347
}
291
348
0 commit comments