@@ -7,7 +7,7 @@ import kotlin.math.*
7
7
/* *
8
8
* [Input] is an abstract base class for synchronous byte readers.
9
9
*
10
- * It contains [ read*] methods to read primitive types ([readByte], [readInt], ...) and arrays ([readByteArray]).
10
+ * It contains ` read*` methods to read primitive types ([readByte], [readInt], ...) and arrays ([readByteArray]).
11
11
*
12
12
* [Input] is buffered. Buffer size depends on [Buffer.size] in the [bufferPool] buffer.
13
13
* Buffer size is [DEFAULT_BUFFER_SIZE] by default.
@@ -20,21 +20,21 @@ import kotlin.math.*
20
20
*
21
21
* To implement [Input] over a custom source, you should override [fill] and [closeSource] methods:
22
22
* ```
23
- * class Input42 : Input() {
24
- * private var closed: Boolean = false
23
+ * class ConstantInput : Input() {
24
+ * private var closed: Boolean = false
25
25
*
26
- * override fun fill(buffer: Buffer): Int {
27
- * if (closed) {
28
- * return 0
29
- * }
26
+ * override fun fill(buffer: Buffer): Int {
27
+ * if (closed) {
28
+ * return 0
29
+ * }
30
30
*
31
- * buffer.storeByteAt(index = 0, value = 42)
32
- * return 1
33
- * }
31
+ * buffer.storeByteAt(index = 0, value = 42)
32
+ * return 1
33
+ * }
34
34
*
35
- * override fun closeSource() {
36
- * closed = true
37
- * }
35
+ * override fun closeSource() {
36
+ * closed = true
37
+ * }
38
38
* }
39
39
* ```
40
40
*
@@ -107,31 +107,28 @@ public abstract class Input : Closeable {
107
107
}
108
108
109
109
/* *
110
- * Constructs a new Input with the default pool of buffers with the given [bufferSize] .
110
+ * Constructs a new Input with the default pool of buffers.
111
111
*/
112
112
protected constructor () : this (DefaultBufferPool .Instance )
113
113
114
114
/* *
115
- * Reads the content of this [Input] to [destination] [Output].
115
+ * Reads the available content in current [Input] to the [destination].
116
+ * If no bytes are available in the input, [fill] method will be called directly on
117
+ * the [destination] underlying buffer without an extra copy.
118
+ * Otherwise, available bytes are copied to the destination.
116
119
*
117
- * If there are no bytes in cache(stored from last [fill] or in [preview]), [fill] will be called on the
118
- * [destination] buffer directly without an extra copy.
119
- *
120
- * If there are bytes in cache, it'll be flushed to [destination].
121
- *
122
- * Please note that if [Input] and [destination] [Output] aren't sharing same [bufferPool]s or [Input] is in
123
- * [preview], bytes will be copied.
120
+ * TODO: fix this one along all the codebase
121
+ * If [Input] and [Output] have different buffer pools, available bytes are copied and
122
+ * no direct transfer is performed
124
123
*/
125
124
public fun readAvailableTo (destination : Output ): Int {
126
125
if (! previewDiscard) {
127
126
return copyAvailableTo(destination)
128
127
}
129
128
130
129
val preview = previewBytes
131
-
132
130
// Do we have single byte in cache?
133
131
if (position != limit || preview != null && previewIndex < preview.tail) {
134
-
135
132
if (bufferPool != = destination.bufferPool) {
136
133
// Can't share buffers between different pools.
137
134
return copyAvailableTo(destination)
@@ -142,15 +139,18 @@ public abstract class Input : Closeable {
142
139
endOffset
143
140
}
144
141
}
145
-
146
142
// No bytes in cache: fill [destination] buffer direct.
147
143
return destination.writeBuffer { buffer, startIndex, endIndex ->
148
144
startIndex + fill(buffer, startIndex, endIndex)
149
145
}
150
146
}
151
147
152
148
/* *
153
- * Attempts to move chunk from this [Input] to the [destination].
149
+ * Reads the available content in current [Input] to the [destination] buffer.
150
+ *
151
+ * If no bytes are available in the input, [fill] method will be called directly on
152
+ * the [destination] buffer without an extra copy.
153
+ * Otherwise, available bytes are copied to the destination.
154
154
*/
155
155
public fun readAvailableTo (
156
156
destination : Buffer ,
@@ -163,7 +163,6 @@ public abstract class Input : Closeable {
163
163
if (position != limit || previewBytes != null ) {
164
164
return copyAvailableTo(destination, startIndex, endIndex)
165
165
}
166
-
167
166
// No bytes in cache: fill [destination] buffer direct.
168
167
return fill(destination, startIndex, endIndex)
169
168
}
@@ -187,9 +186,7 @@ public abstract class Input : Closeable {
187
186
val markPosition = position
188
187
189
188
previewDiscard = false
190
-
191
189
val result = reader()
192
-
193
190
previewDiscard = markDiscard
194
191
position = markPosition
195
192
@@ -209,9 +206,7 @@ public abstract class Input : Closeable {
209
206
}
210
207
211
208
/* *
212
- * Check if at least 1 byte available to read.
213
- *
214
- * The method could block until source provides a byte.
209
+ * Check if at least one byte is available to read.
215
210
*/
216
211
@Suppress(" NOTHING_TO_INLINE" )
217
212
public inline fun eof (): Boolean = ! prefetch(1 )
@@ -278,8 +273,6 @@ public abstract class Input : Closeable {
278
273
while (remaining > 0 ) {
279
274
val skipCount = readBufferRange { _, startOffset, endOffset ->
280
275
val skipCount = min(remaining, endOffset - startOffset)
281
-
282
-
283
276
startOffset + skipCount
284
277
}
285
278
@@ -313,16 +306,13 @@ public abstract class Input : Closeable {
313
306
}
314
307
315
308
/* *
316
- * Requests to fill [buffer] from [startIndex] to [endIndex] exclusive with bytes from source. This method will block and wait
317
- * if no bytes available.
318
- *
319
- * This method copies bytes from source to [buffer] from [startIndex] to [startIndex] + `return-value`. Other bytes
320
- * should not be touched.
309
+ * Requests to fill [buffer] from [startIndex] to [endIndex] exclusive from the underlying source.
310
+ * This method may block and wait if no bytes are available.
311
+ * This method copies bytes from source to [buffer] from [startIndex] to [startIndex] + `return-value`.
321
312
*
322
313
* The [startIndex] cannot be negative, the [endIndex] should be greater than [startIndex]
323
314
* The [buffer] size should be positive, [endIndex] cannot be greater than [buffer] size.
324
- *
325
- * Writing to [buffer] outside of the given range leads to unspecified behaviour.
315
+ * Writing and reading to the [buffer] outside of the given range leads to unspecified behaviour.
326
316
*
327
317
* @return number of bytes were filled (`endIndex - startIndex` at most) or `0` if no more input is available.
328
318
*/
@@ -351,13 +341,22 @@ public abstract class Input : Closeable {
351
341
primitiveSize : Int ,
352
342
readDirect : (buffer: Buffer , offset: Int ) -> Long
353
343
): Long {
344
+ val position = preparePrimitiveReadPosition(primitiveSize)
345
+ if (position != - 1 ) {
346
+ return readDirect(buffer, position)
347
+ }
348
+ // Nope, doesn't fit in a buffer, read byte by byte
349
+ return readPrimitive(primitiveSize)
350
+ }
351
+
352
+ private fun preparePrimitiveReadPosition (primitiveSize : Int ): Int {
354
353
val currentPosition = position
355
354
val currentLimit = limit
356
355
val targetLimit = currentPosition + primitiveSize
357
356
358
357
if (currentLimit >= targetLimit) {
359
358
position = targetLimit
360
- return readDirect(buffer, currentPosition)
359
+ return currentPosition
361
360
}
362
361
363
362
if (currentLimit == currentPosition) {
@@ -370,28 +369,17 @@ public abstract class Input : Closeable {
370
369
// we know we are at zero position here, but limit & buffer could've changed, so can't use cached value
371
370
if (limit >= primitiveSize) {
372
371
position = primitiveSize
373
- return readDirect(buffer, 0 )
372
+ return 0
374
373
}
375
374
}
376
-
377
- // Nope, doesn't fit in a buffer, read byte by byte
378
- var result = 0L
379
- readBytes(primitiveSize) {
380
- result = (result shl 8 ) or it.toLong()
381
- }
382
-
383
- return result
375
+ return - 1
384
376
}
385
377
386
- /* *
387
- * Reads [size] unsigned bytes from an Input and calls [consumer] on each of them.
388
- * @throws EOFException if no more bytes available.
389
- */
390
- private inline fun readBytes (size : Int , consumer : (unsignedByte: Int ) -> Unit ) {
378
+ private fun readPrimitive (size : Int ): Long {
391
379
var remaining = size
392
-
393
380
var current = position
394
381
var currentLimit = limit
382
+ var result = 0L
395
383
while (remaining > 0 ) {
396
384
if (current == currentLimit) {
397
385
if (fetchCachedOrFill() == 0 ) {
@@ -403,14 +391,14 @@ public abstract class Input : Closeable {
403
391
}
404
392
405
393
val byte = buffer.loadByteAt(current).toInt() and 0xFF
406
- consumer(byte)
407
-
394
+ result = (result shl 8 ) or byte.toLong()
408
395
current++
409
396
remaining--
410
397
}
411
398
412
399
position = current
413
400
limit = currentLimit
401
+ return result
414
402
}
415
403
416
404
/* *
0 commit comments