Compare commits

..

6 Commits

Author SHA1 Message Date
2d63de35c0 Add updateTypes to TypedByteArray and bump version to 0.3.6
Introduced an `updateTypes` method to dynamically update type definitions in `TypedByteArray`. Made `definition` private and initialized type/index maps in `createTypeAndIndexMap`. Updated project version for release.
2025-06-22 19:56:22 +02:00
9f152ca8da Fix size calculation to handle negative values and release version 0.3.4 2025-06-22 16:23:53 +02:00
1c23178839 Bump version to 0.3.4-SNAPSHOT for ongoing development. 2025-06-16 19:46:16 +02:00
ab6694ca6a Fix slice bounds check in SlicedByteArray and release version 0.3.3. 2025-06-16 19:46:04 +02:00
ad1fdf366b Bump version to 0.3.3-SNAPSHOT for ongoing development 2025-06-15 16:12:53 +02:00
e1002a5e0b Add slice functionality to SlicedByteArray with tests and edge case validation
Implemented a `slice` method in `SlicedByteArray` to allow creating sub-arrays with specified offset and length. Added validations to handle invalid inputs and bounds. Introduced `SliceTest` to cover standard, edge cases, and error scenarios. Bumped version to 0.3.2.
2025-06-15 16:10:52 +02:00
5 changed files with 134 additions and 5 deletions

View File

@@ -8,7 +8,7 @@ plugins {
}
group = "nl.astraeus"
version = "0.3.0"
version = "0.3.6"
repositories {
mavenCentral()

View File

@@ -1,5 +1,7 @@
package nl.astraeus.tba
import kotlin.math.max
enum class DataType(
val size: Int,
val bytesUsedInternally: Int = 0
@@ -36,6 +38,8 @@ open class ByteArrayDefinition(
val types: List<Type> = types.toList()
val size: Int by lazy {
this.types.sumOf { it.size }
this.types.sumOf {
max(0, it.size)
}
}
}

View File

@@ -185,6 +185,14 @@ class SlicedByteArray(
fun decodeToString(): String = data.decodeToString(offset, offset + length)
fun slice(offset: Int, length: Int): SlicedByteArray {
check(offset >= 0) { "Offset must be non-negative" }
check(length >= 0) { "Length must be non-negative" }
check(offset + length <= this.data.size) { "Offset + length exceeds array bounds (offset: $offset, length: $length, array length: ${this.data.size})" }
return SlicedByteArray(data, this.offset + offset, length)
}
companion object {
fun wrap(
data: ByteArray,

View File

@@ -28,7 +28,7 @@ open class TypedByteArray(
/**
* The definition of the byte array structure.
*/
val definition: ByteArrayDefinition = ByteArrayDefinition(*types)
private var definition: ByteArrayDefinition = ByteArrayDefinition(*types)
/**
* The handler for the underlying byte array data.
@@ -47,14 +47,38 @@ open class TypedByteArray(
val indexMap = mutableMapOf<String, Int>()
init {
createTypeAndIndexMap()
}
fun definitionSize() = definition.size
/**
* Updates the internal structures with the provided types. This method reinitializes
* the necessary definitions, data handlers, and mapping structures based on the input types.
*
* @param types The list of types to update the internal data structures. Each type specifies
* its name, data type, and size. At least one type should be provided.
*
* WARNING: This method is not thread-safe and should be used with extreme caution.
* Updating types at runtime can lead to data corruption and inconsistencies if not handled properly.
*/
fun updateTypes(vararg types: Type) {
definition = ByteArrayDefinition(*types)
data = MutableByteArrayHandler(SlicedByteArray(definition.size))
indexMap.clear()
typeMap.clear()
createTypeAndIndexMap()
}
private fun createTypeAndIndexMap() {
check(definition.size <= data.buffer.length) {
"Size of data can not be smaller then size of definition"
}
var index = 0
for (type in definition.types) {
check (!typeMap.containsKey(type.name)) { "Duplicate type name ${type.name}" }
check (!indexMap.containsKey(type.name)) { "Duplicate type name ${type.name}" }
check(!typeMap.containsKey(type.name)) { "Duplicate type name ${type.name}" }
check(!indexMap.containsKey(type.name)) { "Duplicate type name ${type.name}" }
typeMap[type.name] = type
indexMap[type.name] = index

View File

@@ -0,0 +1,93 @@
package nl.astraeus.tba
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
/**
* Test class for the slice method in SlicedByteArray
*/
class SliceTest {
@Test
fun testSlice() {
// Create a SlicedByteArray with some test data
val array = SlicedByteArray(10)
for (i in 0 until 10) {
array[i] = i.toByte()
}
// Test basic slicing
val slice1 = array.slice(2, 3)
assertEquals(3, slice1.size)
assertEquals(2.toByte(), slice1[0])
assertEquals(3.toByte(), slice1[1])
assertEquals(4.toByte(), slice1[2])
// Test slicing with offset 0
val slice2 = array.slice(0, 5)
assertEquals(5, slice2.size)
for (i in 0 until 5) {
assertEquals(i.toByte(), slice2[i])
}
// Test slicing to the end
val slice3 = array.slice(5, 5)
assertEquals(5, slice3.size)
for (i in 0 until 5) {
assertEquals((i + 5).toByte(), slice3[i])
}
// Test nested slicing
val nestedSlice = slice1.slice(1, 2)
assertEquals(2, nestedSlice.size)
assertEquals(3.toByte(), nestedSlice[0])
assertEquals(4.toByte(), nestedSlice[1])
}
@Test
fun testSliceEdgeCases() {
val array = SlicedByteArray(10)
for (i in 0 until 10) {
array[i] = i.toByte()
}
// Test empty slice
val emptySlice = array.slice(5, 0)
assertEquals(0, emptySlice.size)
// Test slice at the very end
val endSlice = array.slice(9, 1)
assertEquals(1, endSlice.size)
assertEquals(9.toByte(), endSlice[0])
}
@Test
fun testSliceErrorCases() {
val array = SlicedByteArray(10)
// Test negative offset
assertFailsWith<IllegalStateException> {
array.slice(-1, 5)
}
// Test negative length
assertFailsWith<IllegalStateException> {
array.slice(0, -1)
}
// Test offset + length > array.length
assertFailsWith<IllegalStateException> {
array.slice(6, 5)
}
// Test offset = array.length (valid if length = 0)
val emptyEndSlice = array.slice(10, 0)
assertEquals(0, emptyEndSlice.size)
// Test offset > array.length
assertFailsWith<IllegalStateException> {
array.slice(11, 0)
}
}
}