Skip to content

Commit ccbee9a

Browse files
authored
Mitigate unnecessary Encoder.OutFeed allocation when array is empty (#227)
1 parent fadeed8 commit ccbee9a

File tree

4 files changed

+9
-13
lines changed

4 files changed

+9
-13
lines changed

benchmarks/README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@ workflow run on the [GitHub Actions][url-actions] tab of the repository.
1515
./gradlew jvmBenchmark
1616
```
1717

18-
- Run Js:
19-
```shell
20-
./gradlew jsBenchmark
21-
```
22-
2318
- Run WasmJs:
2419
```shell
2520
./gradlew wasmJsBenchmark

library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/Encoder.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ public sealed class Encoder<C: EncoderDecoder.Config>(config: C): Decoder<C>(con
221221
public fun ByteArray.encodeToString(encoder: Encoder<*>): String {
222222
return encoder.encodeOutMaxSizeOrFail(size) { maxSize ->
223223
val sb = StringBuilder(maxSize)
224-
encoder.encode(this, sb::append)
224+
encoder.encode(this, _outFeed = { OutFeed(sb::append) })
225225
val result = sb.toString()
226226
if (encoder.config.backFillBuffers) {
227227
sb.wipe()
@@ -248,7 +248,7 @@ public sealed class Encoder<C: EncoderDecoder.Config>(config: C): Decoder<C>(con
248248
return encoder.encodeOutMaxSizeOrFail(size) block@ { maxSize ->
249249
var i = 0
250250
val a = CharArray(maxSize)
251-
encoder.encode(this) { c -> a[i++] = c }
251+
encoder.encode(this, _outFeed = { OutFeed { c -> a[i++] = c } })
252252
if (i == maxSize) return@block a
253253
val copy = a.copyOf(i)
254254
if (encoder.config.backFillBuffers) {
@@ -274,7 +274,7 @@ public sealed class Encoder<C: EncoderDecoder.Config>(config: C): Decoder<C>(con
274274
return encoder.encodeOutMaxSizeOrFail(size) block@ { maxSize ->
275275
var i = 0
276276
val a = ByteArray(maxSize)
277-
encoder.encode(this) { char -> a[i++] = char.code.toByte() }
277+
encoder.encode(this, _outFeed = { OutFeed { char -> a[i++] = char.code.toByte() } })
278278
if (i == maxSize) return@block a
279279
val copy = a.copyOf(i)
280280
if (encoder.config.backFillBuffers) {

library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/EncoderDecoder.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,6 @@ private inline fun checkMaxEmitSize(size: Int, parameterName: () -> String) {
807807
}
808808

809809
@Suppress("NOTHING_TO_INLINE")
810-
internal inline fun negativeEncodingSizeException(outSize: Number): EncodingSizeException {
810+
private inline fun negativeEncodingSizeException(outSize: Number): EncodingSizeException {
811811
return EncodingSizeException("Calculated output of Size[$outSize] was negative")
812812
}

library/core/src/commonMain/kotlin/io/matthewnelson/encoding/core/internal/-Encoder.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
**/
16-
@file:Suppress("LocalVariableName", "NOTHING_TO_INLINE")
16+
@file:Suppress("LocalVariableName")
1717

1818
package io.matthewnelson.encoding.core.internal
1919

@@ -37,19 +37,20 @@ internal inline fun <T: Any> Encoder<*>.encodeOutMaxSizeOrFail(
3737
_block: (maxSize: Int) -> T,
3838
): T {
3939
contract { callsInPlace(_block, InvocationKind.AT_MOST_ONCE) }
40-
4140
val maxSize = config.encodeOutMaxSize(size.toLong())
4241
if (maxSize > MAX_ENCODE_OUT_SIZE) {
4342
throw Config.outSizeExceedsMaxEncodingSizeException(maxSize, MAX_ENCODE_OUT_SIZE)
4443
}
45-
4644
return _block(maxSize.toInt())
4745
}
4846

47+
@OptIn(ExperimentalContracts::class)
4948
internal inline fun <C: Config> Encoder<C>.encode(
5049
data: ByteArray,
51-
out: Encoder.OutFeed,
50+
_outFeed: () -> Encoder.OutFeed,
5251
) {
52+
contract { callsInPlace(_outFeed, InvocationKind.AT_MOST_ONCE) }
5353
if (data.isEmpty()) return
54+
val out = _outFeed()
5455
newEncoderFeed(out).use { feed -> data.forEach { b -> feed.consume(b) } }
5556
}

0 commit comments

Comments
 (0)