Skip to content

Commit b93b188

Browse files
authored
Use ByteArray.copyInto instead of loops when processing buffered data (#70)
1 parent 43bdf61 commit b93b188

File tree

3 files changed

+91
-102
lines changed
  • library/digest/src
    • commonMain/kotlin/org/kotlincrypto/core/digest/internal
    • jvmMain/kotlin/org/kotlincrypto/core/digest
    • nonJvmMain/kotlin/org/kotlincrypto/core/digest

3 files changed

+91
-102
lines changed

library/digest/src/commonMain/kotlin/org/kotlincrypto/core/digest/internal/-Buffer.kt

+57-64
Original file line numberDiff line numberDiff line change
@@ -73,92 +73,85 @@ internal value class Buffer private constructor(internal val value: ByteArray) {
7373
}
7474

7575
@Suppress("NOTHING_TO_INLINE")
76-
internal inline fun Buffer.update(
76+
internal inline fun Buffer.commonUpdate(
7777
input: Byte,
78-
bufOffsGetAndIncrement: () -> Int,
79-
bufOffsReset: () -> Unit,
80-
compress: (buf: ByteArray, offset: Int) -> Unit,
81-
compressCountIncrement: () -> Unit,
78+
bufOffsPlusPlus: Int,
79+
doCompression: (buf: ByteArray, offset: Int) -> Unit,
8280
) {
83-
val bufOffs = bufOffsGetAndIncrement()
84-
value[bufOffs] = input
85-
86-
// value.size == blockSize
87-
if ((bufOffs + 1) != value.size) return
88-
compress(value, 0)
89-
compressCountIncrement()
90-
bufOffsReset()
81+
val buf = value
82+
buf[bufOffsPlusPlus] = input
83+
84+
// buf.size == blockSize
85+
if ((bufOffsPlusPlus + 1) != buf.size) return
86+
doCompression(buf, 0)
9187
}
9288

9389
@Suppress("NOTHING_TO_INLINE")
94-
internal inline fun Buffer.update(
90+
internal inline fun Buffer.commonUpdate(
9591
input: ByteArray,
9692
offset: Int,
9793
len: Int,
98-
bufOffsGet: () -> Int,
99-
bufOffsGetAndIncrement: () -> Int,
100-
bufOffsReset: () -> Unit,
94+
bufOffs: Int,
95+
bufOffsSet: (value: Int) -> Unit,
10196
compress: (buf: ByteArray, offset: Int) -> Unit,
102-
compressCountIncrement: () -> Unit,
97+
compressCountAdd: (value: Int) -> Unit,
10398
) {
104-
var i = offset
105-
var remaining = len
106-
107-
// Fill buffer if not already empty
108-
while (bufOffsGet() != 0 && remaining > 0) {
109-
update(
110-
input[i++],
111-
bufOffsGetAndIncrement,
112-
bufOffsReset,
113-
compress,
114-
compressCountIncrement,
115-
)
116-
--remaining
117-
}
99+
val buf = value
100+
val blockSize = buf.size
101+
var offsInput = offset
102+
val limit = offsInput + len
103+
var offsBuf = bufOffs
104+
var compressions = 0
105+
106+
if (offsBuf > 0) {
107+
// Need to use buffered data (if possible)
108+
109+
if (offsBuf + len < blockSize) {
110+
// Not enough for a compression. Add it to the buffer.
111+
input.copyInto(buf, offsBuf, offsInput, limit)
112+
bufOffsSet(offsBuf + len)
113+
return
114+
}
118115

119-
// Chunk
120-
while (remaining >= value.size) {
121-
compress(input, i)
122-
i += value.size
123-
remaining -= value.size
124-
compressCountIncrement()
116+
// Add enough input to do a compression
117+
val needed = blockSize - offsBuf
118+
input.copyInto(buf, offsBuf, offsInput, offsInput + needed)
119+
compress(buf, 0)
120+
offsBuf = 0
121+
offsInput += needed
122+
compressions++
125123
}
126124

127-
// Add remaining to buffer
128-
while (remaining-- > 0) {
129-
update(
130-
input[i++],
131-
bufOffsGetAndIncrement,
132-
bufOffsReset,
133-
compress,
134-
compressCountIncrement,
135-
)
125+
// Chunk blocks (if possible)
126+
while (offsInput < limit) {
127+
val offsNext = offsInput + blockSize
128+
129+
if (offsNext > limit) {
130+
// Not enough for a compression. Add it to the buffer.
131+
input.copyInto(buf, 0, offsInput, limit)
132+
offsBuf = limit - offsInput
133+
break
134+
}
135+
136+
compress(input, offsInput)
137+
compressions++
138+
offsInput = offsNext
136139
}
140+
141+
// Update globals
142+
bufOffsSet(offsBuf)
143+
compressCountAdd(compressions)
137144
}
138145

139146
@Suppress("NOTHING_TO_INLINE")
140-
internal inline fun Buffer.digest(
147+
internal inline fun Buffer.commonDigest(
141148
bufOffs: Int,
142149
compressCount: Long,
143150
digest: (bitLength: Long, offs: Int, buf: ByteArray) -> ByteArray,
144-
resetBufOffs: () -> Unit,
145-
resetCompressCount: () -> Unit,
146-
resetDigest: () -> Unit,
151+
reset: () -> Unit,
147152
): ByteArray {
148153
val bitLength = ((compressCount * value.size) + bufOffs) * 8
149154
val final = digest(bitLength, bufOffs, value)
150-
reset(resetBufOffs, resetCompressCount, resetDigest)
155+
reset()
151156
return final
152157
}
153-
154-
@Suppress("NOTHING_TO_INLINE")
155-
internal inline fun Buffer.reset(
156-
resetBufOffs: () -> Unit,
157-
resetCompressCount: () -> Unit,
158-
resetDigest: () -> Unit,
159-
) {
160-
value.fill(0)
161-
resetBufOffs()
162-
resetCompressCount()
163-
resetDigest()
164-
}

library/digest/src/jvmMain/kotlin/org/kotlincrypto/core/digest/Digest.kt

+17-19
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,11 @@ public actual abstract class Digest: MessageDigest, Algorithm, Cloneable, Copyab
9999
updateDigest(input, offset, len)
100100
}
101101

102-
public actual final override fun digest(): ByteArray = buf.digest(
102+
public actual final override fun digest(): ByteArray = buf.commonDigest(
103103
bufOffs = bufOffs,
104104
compressCount = compressCount,
105105
digest = ::digest,
106-
resetBufOffs = { bufOffs = 0 },
107-
resetCompressCount = { compressCount = 0 },
108-
resetDigest = ::resetDigest,
106+
reset = ::reset,
109107
)
110108
public actual final override fun digest(input: ByteArray): ByteArray {
111109
updateDigest(input, 0, input.size)
@@ -115,11 +113,10 @@ public actual abstract class Digest: MessageDigest, Algorithm, Cloneable, Copyab
115113
public final override fun digest(buf: ByteArray, offset: Int, len: Int): Int = super.digest(buf, offset, len)
116114

117115
public actual final override fun reset() {
118-
buf.reset(
119-
resetBufOffs = { bufOffs = 0 },
120-
resetCompressCount = { compressCount = 0 },
121-
resetDigest = ::resetDigest,
122-
)
116+
buf.value.fill(0)
117+
bufOffs = 0
118+
compressCount = 0
119+
resetDigest()
123120
}
124121

125122
public final override fun clone(): Any = copy()
@@ -145,12 +142,14 @@ public actual abstract class Digest: MessageDigest, Algorithm, Cloneable, Copyab
145142
* if necessary.
146143
* */
147144
protected actual open fun updateDigest(input: Byte) {
148-
buf.update(
145+
buf.commonUpdate(
149146
input = input,
150-
bufOffsGetAndIncrement = { bufOffs++ },
151-
bufOffsReset = { bufOffs = 0 },
152-
compress = ::compress,
153-
compressCountIncrement = { compressCount++ },
147+
bufOffsPlusPlus = bufOffs++,
148+
doCompression = { buf, offset ->
149+
compress(buf, offset)
150+
bufOffs = 0
151+
compressCount++
152+
},
154153
)
155154
}
156155

@@ -160,15 +159,14 @@ public actual abstract class Digest: MessageDigest, Algorithm, Cloneable, Copyab
160159
* override and intercept if necessary.
161160
* */
162161
protected actual open fun updateDigest(input: ByteArray, offset: Int, len: Int) {
163-
buf.update(
162+
buf.commonUpdate(
164163
input = input,
165164
offset = offset,
166165
len = len,
167-
bufOffsGet = { bufOffs },
168-
bufOffsGetAndIncrement = { bufOffs++ },
169-
bufOffsReset = { bufOffs = 0 },
166+
bufOffs = bufOffs,
167+
bufOffsSet = { bufOffs = it },
170168
compress = ::compress,
171-
compressCountIncrement = { compressCount++ },
169+
compressCountAdd = { compressCount += it },
172170
)
173171
}
174172

library/digest/src/nonJvmMain/kotlin/org/kotlincrypto/core/digest/Digest.kt

+17-19
Original file line numberDiff line numberDiff line change
@@ -95,25 +95,22 @@ public actual abstract class Digest: Algorithm, Copyable<Digest>, Resettable, Up
9595
updateDigest(input, offset, len)
9696
}
9797

98-
public actual fun digest(): ByteArray = buf.digest(
98+
public actual fun digest(): ByteArray = buf.commonDigest(
9999
bufOffs = bufOffs,
100100
compressCount = compressCount,
101101
digest = ::digest,
102-
resetBufOffs = { bufOffs = 0 },
103-
resetCompressCount = { compressCount = 0 },
104-
resetDigest = ::resetDigest,
102+
reset = ::reset,
105103
)
106104
public actual fun digest(input: ByteArray): ByteArray {
107105
updateDigest(input, 0, input.size)
108106
return digest()
109107
}
110108

111109
public actual final override fun reset() {
112-
buf.reset(
113-
resetBufOffs = { bufOffs = 0 },
114-
resetCompressCount = { compressCount = 0 },
115-
resetDigest = ::resetDigest,
116-
)
110+
buf.value.fill(0)
111+
bufOffs = 0
112+
compressCount = 0
113+
resetDigest()
117114
}
118115

119116
public actual final override fun copy(): Digest = buf.toState(
@@ -138,12 +135,14 @@ public actual abstract class Digest: Algorithm, Copyable<Digest>, Resettable, Up
138135
* if necessary.
139136
* */
140137
protected actual open fun updateDigest(input: Byte) {
141-
buf.update(
138+
buf.commonUpdate(
142139
input = input,
143-
bufOffsGetAndIncrement = { bufOffs++ },
144-
bufOffsReset = { bufOffs = 0 },
145-
compress = ::compress,
146-
compressCountIncrement = { compressCount++ },
140+
bufOffsPlusPlus = bufOffs++,
141+
doCompression = { buf, offset ->
142+
compress(buf, offset)
143+
bufOffs = 0
144+
compressCount++
145+
},
147146
)
148147
}
149148

@@ -153,15 +152,14 @@ public actual abstract class Digest: Algorithm, Copyable<Digest>, Resettable, Up
153152
* override and intercept if necessary.
154153
* */
155154
protected actual open fun updateDigest(input: ByteArray, offset: Int, len: Int) {
156-
buf.update(
155+
buf.commonUpdate(
157156
input = input,
158157
offset = offset,
159158
len = len,
160-
bufOffsGet = { bufOffs },
161-
bufOffsGetAndIncrement = { bufOffs++ },
162-
bufOffsReset = { bufOffs = 0 },
159+
bufOffs = bufOffs,
160+
bufOffsSet = { bufOffs = it },
163161
compress = ::compress,
164-
compressCountIncrement = { compressCount++ },
162+
compressCountAdd = { compressCount += it },
165163
)
166164
}
167165

0 commit comments

Comments
 (0)