FragmentedArrayFloatList: fix broken batch adding in rare cases + test

This commit is contained in:
Moritz Zwerger 2023-10-21 20:25:56 +02:00
parent c714fe483e
commit ae1a8562de
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
2 changed files with 76 additions and 23 deletions

View File

@ -47,14 +47,18 @@ class FragmentedArrayFloatList(
if (needed == 0) {
return
}
grow(needed)
tryGrow(needed)
}
private fun grow(size: Int): FloatBuffer {
private fun tryGrow(size: Int): FloatBuffer {
if (finished) throw IllegalStateException()
if (limit - this.size >= size) {
return this.incomplete[0]
}
return grow(size)
}
private fun grow(size: Int): FloatBuffer {
val grow = if (nextGrowStep < size) {
(size / nextGrowStep + 1) * nextGrowStep
} else {
@ -71,46 +75,63 @@ class FragmentedArrayFloatList(
}
override fun add(value: Float) {
val buffer = grow(1)
val buffer = tryGrow(1)
buffer.put(value)
size += 1
tryPush(buffer)
invalidateOutput()
}
private fun batchAdd(value: Float, buffer: FloatBuffer, left: Int): FloatBuffer {
buffer.put(value)
if (!tryPush(buffer)) {
return buffer
}
if (left == 0) return buffer
return grow(left)
}
fun add(value1: Float, value2: Float) {
var buffer = grow(2)
buffer.put(value1); if (tryPush(buffer)) buffer = grow(1)
buffer.put(value2)
var buffer = tryGrow(1)
buffer = batchAdd(value1, buffer, 1)
batchAdd(value2, buffer, 0)
size += 2
tryPush(buffer)
invalidateOutput()
}
fun add(value1: Float, value2: Float, value3: Float) {
var buffer = grow(3)
buffer.put(value1); if (tryPush(buffer)) buffer = grow(2)
buffer.put(value2); if (tryPush(buffer)) buffer = grow(1)
buffer.put(value3)
var buffer = tryGrow(1)
buffer = batchAdd(value1, buffer, 2)
buffer = batchAdd(value2, buffer, 1)
batchAdd(value3, buffer, 0)
size += 3
tryPush(buffer)
invalidateOutput()
}
fun add(value1: Float, value2: Float, value3: Float, value4: Float) {
var buffer = tryGrow(1)
buffer = batchAdd(value1, buffer, 3)
buffer = batchAdd(value2, buffer, 2)
buffer = batchAdd(value3, buffer, 1)
batchAdd(value4, buffer, 0)
size += 4
invalidateOutput()
}
fun add(value1: Float, value2: Float, value3: Float, value4: Float, value5: Float, value6: Float, value7: Float) {
var buffer = grow(7)
buffer.put(value1); if (tryPush(buffer)) buffer = grow(6)
buffer.put(value2); if (tryPush(buffer)) buffer = grow(5)
buffer.put(value3); if (tryPush(buffer)) buffer = grow(4)
buffer.put(value4); if (tryPush(buffer)) buffer = grow(3)
buffer.put(value5); if (tryPush(buffer)) buffer = grow(2)
buffer.put(value6); if (tryPush(buffer)) buffer = grow(1)
buffer.put(value7)
var buffer = tryGrow(1)
buffer = batchAdd(value1, buffer, 6)
buffer = batchAdd(value2, buffer, 5)
buffer = batchAdd(value3, buffer, 4)
buffer = batchAdd(value4, buffer, 3)
buffer = batchAdd(value5, buffer, 2)
buffer = batchAdd(value6, buffer, 1)
batchAdd(value7, buffer, 0)
size += 7
tryPush(buffer)
invalidateOutput()
}
@ -147,7 +168,7 @@ class FragmentedArrayFloatList(
}
size += offset
val length = array.size - offset
val next = grow(length)
val next = tryGrow(length)
next.put(array, offset, length)
size += length
next.position(length)
@ -179,7 +200,7 @@ class FragmentedArrayFloatList(
}
size += offset
val length = position - offset
val next = grow(length)
val next = tryGrow(length)
buffer.copy(offset, next, 0, length)
next.position(length)
size += length

View File

@ -15,6 +15,7 @@ package de.bixilon.minosoft.util.collections.floats
import de.bixilon.kutil.collections.primitive.floats.AbstractFloatList
import org.junit.jupiter.api.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
class FragmentedFloatListTest : DirectFloatListTest() {
@ -53,4 +54,35 @@ class FragmentedFloatListTest : DirectFloatListTest() {
assertEquals(14, list.complete.size)
assertEquals(0, list.incomplete.size)
}
@Test
fun `batch adding 7 floats`() {
val list = FragmentedArrayFloatList(1)
for (i in 0 until 100) {
val offset = i * 7.0f
list.add(offset + 0, offset + 1, offset + 2, offset + 3, offset + 4, offset + 5, offset + 6)
}
assertEquals(list.size, 700)
val expected = FloatArray(700) { it.toFloat() }
println(expected.contentToString())
val array = list.toArray()
println(array.contentToString())
assertContentEquals(expected, array)
}
@Test
fun `batch adding float array`() {
val list = FragmentedArrayFloatList(1)
for (i in 0 until 100) {
val offset = i * 7.0f
val a = floatArrayOf(offset + 0, offset + 1, offset + 2, offset + 3, offset + 4, offset + 5, offset + 6)
list += a
}
assertEquals(list.size, 700)
val expected = FloatArray(700) { it.toFloat() }
println(expected.contentToString())
val array = list.toArray()
println(array.contentToString())
assertContentEquals(expected, array)
}
}