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) { if (needed == 0) {
return return
} }
grow(needed) tryGrow(needed)
} }
private fun grow(size: Int): FloatBuffer { private fun tryGrow(size: Int): FloatBuffer {
if (finished) throw IllegalStateException() if (finished) throw IllegalStateException()
if (limit - this.size >= size) { if (limit - this.size >= size) {
return this.incomplete[0] return this.incomplete[0]
} }
return grow(size)
}
private fun grow(size: Int): FloatBuffer {
val grow = if (nextGrowStep < size) { val grow = if (nextGrowStep < size) {
(size / nextGrowStep + 1) * nextGrowStep (size / nextGrowStep + 1) * nextGrowStep
} else { } else {
@ -71,46 +75,63 @@ class FragmentedArrayFloatList(
} }
override fun add(value: Float) { override fun add(value: Float) {
val buffer = grow(1) val buffer = tryGrow(1)
buffer.put(value) buffer.put(value)
size += 1 size += 1
tryPush(buffer) tryPush(buffer)
invalidateOutput() 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) { fun add(value1: Float, value2: Float) {
var buffer = grow(2) var buffer = tryGrow(1)
buffer.put(value1); if (tryPush(buffer)) buffer = grow(1) buffer = batchAdd(value1, buffer, 1)
buffer.put(value2) batchAdd(value2, buffer, 0)
size += 2 size += 2
tryPush(buffer)
invalidateOutput() invalidateOutput()
} }
fun add(value1: Float, value2: Float, value3: Float) { fun add(value1: Float, value2: Float, value3: Float) {
var buffer = grow(3) var buffer = tryGrow(1)
buffer.put(value1); if (tryPush(buffer)) buffer = grow(2) buffer = batchAdd(value1, buffer, 2)
buffer.put(value2); if (tryPush(buffer)) buffer = grow(1) buffer = batchAdd(value2, buffer, 1)
buffer.put(value3) batchAdd(value3, buffer, 0)
size += 3 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() invalidateOutput()
} }
fun add(value1: Float, value2: Float, value3: Float, value4: Float, value5: Float, value6: Float, value7: Float) { fun add(value1: Float, value2: Float, value3: Float, value4: Float, value5: Float, value6: Float, value7: Float) {
var buffer = grow(7) var buffer = tryGrow(1)
buffer.put(value1); if (tryPush(buffer)) buffer = grow(6) buffer = batchAdd(value1, buffer, 6)
buffer.put(value2); if (tryPush(buffer)) buffer = grow(5) buffer = batchAdd(value2, buffer, 5)
buffer.put(value3); if (tryPush(buffer)) buffer = grow(4) buffer = batchAdd(value3, buffer, 4)
buffer.put(value4); if (tryPush(buffer)) buffer = grow(3) buffer = batchAdd(value4, buffer, 3)
buffer.put(value5); if (tryPush(buffer)) buffer = grow(2) buffer = batchAdd(value5, buffer, 2)
buffer.put(value6); if (tryPush(buffer)) buffer = grow(1) buffer = batchAdd(value6, buffer, 1)
buffer.put(value7) batchAdd(value7, buffer, 0)
size += 7 size += 7
tryPush(buffer)
invalidateOutput() invalidateOutput()
} }
@ -147,7 +168,7 @@ class FragmentedArrayFloatList(
} }
size += offset size += offset
val length = array.size - offset val length = array.size - offset
val next = grow(length) val next = tryGrow(length)
next.put(array, offset, length) next.put(array, offset, length)
size += length size += length
next.position(length) next.position(length)
@ -179,7 +200,7 @@ class FragmentedArrayFloatList(
} }
size += offset size += offset
val length = position - offset val length = position - offset
val next = grow(length) val next = tryGrow(length)
buffer.copy(offset, next, 0, length) buffer.copy(offset, next, 0, length)
next.position(length) next.position(length)
size += 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 de.bixilon.kutil.collections.primitive.floats.AbstractFloatList
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals import kotlin.test.assertEquals
class FragmentedFloatListTest : DirectFloatListTest() { class FragmentedFloatListTest : DirectFloatListTest() {
@ -53,4 +54,35 @@ class FragmentedFloatListTest : DirectFloatListTest() {
assertEquals(14, list.complete.size) assertEquals(14, list.complete.size)
assertEquals(0, list.incomplete.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)
}
} }