position datatypes: fix overflow when adding from -1

This commit is contained in:
Moritz Zwerger 2025-03-31 14:43:56 +02:00
parent 76f39bd426
commit d711e077b7
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
8 changed files with 160 additions and 30 deletions

View File

@ -39,50 +39,67 @@ value class BlockPosition(
inline val y: Int get() = (((raw ushr SHIFT_Y).toInt() and MASK_Y) shl (Int.SIZE_BITS - BITS_Y)) shr (Int.SIZE_BITS - BITS_Y)
inline val z: Int get() = (((raw ushr SHIFT_Z).toInt() and MASK_Z) shl (Int.SIZE_BITS - BITS_Z)) shr (Int.SIZE_BITS - BITS_Z)
inline fun modify(other: Long, component: Long, add: Long): BlockPosition {
val bc = raw and other
val a = ((raw and component) + add) and component
return BlockPosition(bc or a)
}
inline fun modifyX(modify: Long): BlockPosition {
return modify((Integer.toUnsignedLong(MASK_Y) shl SHIFT_Y) or (Integer.toUnsignedLong(MASK_Z) shl SHIFT_Z), Integer.toUnsignedLong(MASK_X) shl SHIFT_X, modify)
}
inline fun modifyY(modify: Long): BlockPosition {
return modify((Integer.toUnsignedLong(MASK_X) shl SHIFT_X) or (Integer.toUnsignedLong(MASK_Z) shl SHIFT_Z), Integer.toUnsignedLong(MASK_Y) shl SHIFT_Y, modify)
}
inline fun modifyZ(modify: Long): BlockPosition {
return modify((Integer.toUnsignedLong(MASK_X) shl SHIFT_X) or (Integer.toUnsignedLong(MASK_Y) shl SHIFT_Y), Integer.toUnsignedLong(MASK_Z) shl SHIFT_Z, modify)
}
inline fun plusX(): BlockPosition {
assertPosition(this.x < MAX_X)
return BlockPosition(raw + X * 1)
return modifyX(X * 1)
}
inline fun plusX(x: Int): BlockPosition {
assertPosition(this.x + x, -MAX_X, MAX_X)
return BlockPosition(raw + X * x)
return modifyX(X * x)
}
inline fun minusX(): BlockPosition {
assertPosition(this.x > -MAX_X)
return BlockPosition(raw - X * 1)
return modifyX(-X * 1)
}
inline fun plusY(): BlockPosition {
assertPosition(this.y < MAX_Y)
return BlockPosition(raw + Y * 1)
return modifyY(Y * 1)
}
inline fun plusY(y: Int): BlockPosition {
assertPosition(this.y + y, MIN_Y, MAX_Y)
return BlockPosition(raw + Y * y)
return modifyY(Y * y)
}
inline fun minusY(): BlockPosition {
assertPosition(this.y > -MAX_Y)
return BlockPosition(raw - Y * 1)
return modifyY(-Y * 1)
}
inline fun plusZ(): BlockPosition {
assertPosition(this.z < MAX_Y)
return BlockPosition(raw + Z * 1)
return modifyZ(Z * 1)
}
inline fun plusZ(z: Int): BlockPosition {
assertPosition(this.z + z, -MAX_Z, MAX_Z)
return BlockPosition(raw + Z * z)
return modifyZ(Z * z)
}
inline fun minusZ(): BlockPosition {
assertPosition(this.z > -MAX_Z)
return BlockPosition(raw - Z * 1)
return modifyZ(-Z * 1)
}
inline fun with(x: Int = this.x, y: Int = this.y, z: Int = this.z) = BlockPosition(x, y, z)

View File

@ -34,35 +34,49 @@ value class ChunkPosition(
inline val x: Int get() = (raw ushr SHIFT_X).toInt() and MASK_X
inline val z: Int get() = (raw ushr SHIFT_Z).toInt() and MASK_Z
inline fun modify(other: Long, component: Long, add: Long): ChunkPosition {
val bc = raw and other
val a = ((raw and component) + add) and component
return ChunkPosition(bc or a)
}
inline fun modifyX(modify: Long): ChunkPosition {
return modify(Integer.toUnsignedLong(MASK_Z) shl SHIFT_Z, Integer.toUnsignedLong(MASK_X) shl SHIFT_X, modify)
}
inline fun modifyZ(modify: Long): ChunkPosition {
return modify(Integer.toUnsignedLong(MASK_X) shl SHIFT_X, Integer.toUnsignedLong(MASK_Z) shl SHIFT_Z, modify)
}
inline fun plusX(): ChunkPosition {
assertPosition(this.x < MAX_X)
return ChunkPosition(raw + X * 1)
return modifyX(X * 1)
}
inline fun plusX(x: Int): ChunkPosition {
assertPosition(this.x + x, -MAX_X, MAX_X)
return ChunkPosition(raw + X * x)
return modifyX(X * x)
}
inline fun minusX(): ChunkPosition {
assert(this.x > -MAX_X)
return ChunkPosition(raw - X * 1)
return modifyX(-X * 1)
}
inline fun plusZ(): ChunkPosition {
assert(this.z < MAX_Z)
return ChunkPosition(raw + Z * 1)
return modifyZ(Z * 1)
}
inline fun plusZ(z: Int): ChunkPosition {
assertPosition(this.z + z, -MAX_Z, MAX_Z)
return ChunkPosition(raw + Z * z)
return modifyZ(Z * z)
}
inline fun minusZ(): ChunkPosition {
assert(this.z > -MAX_Z)
return ChunkPosition(raw - Z * 1)
return modifyZ(-Z * 1)
}
inline fun with(x: Int = this.x, z: Int = this.z) = ChunkPosition(x, z)

View File

@ -39,6 +39,15 @@ value class InChunkPosition(
inline val z: Int get() = (raw ushr SHIFT_Z) and MASK_Z
inline val xz: Int get() = raw and ((MASK_X shl SHIFT_X) or (MASK_Z shl SHIFT_Z))
inline fun modify(other: Int, component: Int, add: Int): InChunkPosition {
val bc = raw and other
val a = ((raw and component) + add) and component
return InChunkPosition(bc or a)
}
inline fun modifyY(modify: Int): InChunkPosition {
return modify((MASK_X shl SHIFT_X) or (MASK_Z shl SHIFT_Z), MASK_Y shl SHIFT_Y, modify)
}
inline fun plusX(): InChunkPosition {
assertPosition(this.x < ProtocolDefinition.SECTION_MAX_X)
@ -57,17 +66,17 @@ value class InChunkPosition(
inline fun plusY(): InChunkPosition {
assertPosition(this.y < ProtocolDefinition.CHUNK_MAX_Y)
return InChunkPosition(raw + Y * 1)
return modifyY(Y * 1)
}
inline fun plusY(y: Int): InChunkPosition {
assertPosition(this.y + y, ProtocolDefinition.CHUNK_MIN_Y, ProtocolDefinition.CHUNK_MAX_Y)
return InChunkPosition(raw + Y * y)
return modifyY(Y * y)
}
inline fun minusY(): InChunkPosition {
assertPosition(this.y > ProtocolDefinition.CHUNK_MIN_Y)
return InChunkPosition(raw - Y * 1)
return modifyY(-Y * 1)
}
inline fun plusZ(): InChunkPosition {

View File

@ -35,49 +35,68 @@ value class SectionPosition(
inline val y: SectionHeight get() = (((raw ushr SHIFT_Y).toInt() and MASK_Y) shl (Int.SIZE_BITS - BITS_Y)) shr (Int.SIZE_BITS - BITS_Y)
inline val z: Int get() = (((raw ushr SHIFT_Z).toInt() and MASK_Z) shl (Int.SIZE_BITS - BITS_Z)) shr (Int.SIZE_BITS - BITS_Z)
inline fun modify(other: Long, component: Long, add: Long): SectionPosition {
val bc = raw and other
val a = ((raw and component) + add) and component
return SectionPosition(bc or a)
}
inline fun modifyX(modify: Long): SectionPosition {
return modify((Integer.toUnsignedLong(MASK_Y) shl SHIFT_Y) or (Integer.toUnsignedLong(MASK_Z) shl SHIFT_Z), Integer.toUnsignedLong(MASK_X) shl SHIFT_X, modify)
}
inline fun modifyY(modify: Long): SectionPosition {
return modify((Integer.toUnsignedLong(MASK_X) shl SHIFT_X) or (Integer.toUnsignedLong(MASK_Z) shl SHIFT_Z), Integer.toUnsignedLong(MASK_Y) shl SHIFT_Y, modify)
}
inline fun modifyZ(modify: Long): SectionPosition {
return modify((Integer.toUnsignedLong(MASK_X) shl SHIFT_X) or (Integer.toUnsignedLong(MASK_Y) shl SHIFT_Y), Integer.toUnsignedLong(MASK_Z) shl SHIFT_Z, modify)
}
inline fun plusX(): SectionPosition {
assertPosition(this.x < MAX_X)
return SectionPosition(raw + X * 1)
return modifyX(X * 1)
}
inline fun plusX(x: Int): SectionPosition {
assertPosition(this.x + x, -MAX_X, MAX_X)
return SectionPosition(raw + X * x)
return modifyX(X * x)
}
inline fun minusX(): SectionPosition {
assert(this.x > -MAX_X)
return SectionPosition(raw - X * 1)
return modifyX(-X * 1)
}
inline fun plusY(): SectionPosition {
assertPosition(this.y < MAX_Y)
return SectionPosition(raw + Y * 1)
return modifyY(Y * 1)
}
inline fun plusY(y: Int): SectionPosition {
assertPosition(this.y + y, MIN_Y, MAX_Y)
return SectionPosition(raw + Y * y)
return modifyY(Y * y)
}
inline fun minusY(): SectionPosition {
assert(this.y > MIN_Y)
return SectionPosition(raw - Y * 1)
return modifyY(-Y * 1)
}
inline fun plusZ(): SectionPosition {
assert(this.z < MAX_Z)
return SectionPosition(raw + Z * 1)
return modifyZ(Z * 1)
}
inline fun plusZ(z: Int): SectionPosition {
assertPosition(this.z + z, -MAX_Z, MAX_Z)
return SectionPosition(raw + Z * z)
return modifyZ(Z * z)
}
inline fun minusZ(): SectionPosition {
assert(this.z > -MAX_Z)
return SectionPosition(raw - Z * 1)
return modifyZ(-Z * 1)
}
inline fun with(x: Int = this.x, y: Int = this.y, z: Int = this.z) = SectionPosition(x, y, z)

View File

@ -66,6 +66,18 @@ class BlockPositionTest {
assertEquals(position.plusX().x, 3)
}
@Test
fun `correct plus negative x`() {
val position = BlockPosition(-2, 0xF, 0xF).plusX()
assertEquals(position, BlockPosition(-1, 0xF, 0xF))
}
@Test
fun `correct plus zero x`() {
val position = BlockPosition(-1, 0xF, 0xF).plusX()
assertEquals(position, BlockPosition(0, 0xF, 0xF))
}
@Test
fun `correct plus 2 x`() {
val position = BlockPosition(2, 0xF, 0xF)
@ -114,6 +126,18 @@ class BlockPositionTest {
assertEquals(position.plusY(2).y, 4)
}
@Test
fun `correct plus negative y`() {
val position = BlockPosition(0xF, -2, 0xF).plusY()
assertEquals(position, BlockPosition(0xF, -1, 0xF))
}
@Test
fun `correct plus zero y`() {
val position = BlockPosition(0xF, -1, 0xF).plusY()
assertEquals(position, BlockPosition(0xF, 0, 0xF))
}
@Test
fun `correct minus y`() {
val position = BlockPosition(0xF, 2, 0xF)
@ -153,8 +177,20 @@ class BlockPositionTest {
@Test
fun `correct plus 2 z`() {
val position = BlockPosition(0xF, 0xF, 2)
assertEquals(position.plusZ(2).z, 4)
val position = BlockPosition(0xF, 0xF, 2).plusZ(2)
assertEquals(position, BlockPosition(0xF, 0xF, 4))
}
@Test
fun `correct plus negative z`() {
val position = BlockPosition(0xF, 0xF, -2).plusZ()
assertEquals(position, BlockPosition(0xF, 0xF, -1))
}
@Test
fun `correct plus zero z`() {
val position = BlockPosition(0xF, 0xF, -1).plusZ()
assertEquals(position, BlockPosition(0xF, 0xF, 0))
}
@Test

View File

@ -66,6 +66,12 @@ class ChunkPositionTest {
assertEquals(position.plusX().x, 3)
}
@Test
fun `correct plus negative x`() {
val position = ChunkPosition(-1, 0xF).plusX()
assertEquals(position, ChunkPosition(0, 0xF))
}
@Test
fun `correct plus 2 x`() {
val position = ChunkPosition(2, 0xF)
@ -108,6 +114,12 @@ class ChunkPositionTest {
assertEquals(position.plusZ().z, 3)
}
@Test
fun `correct plus negative z`() {
val position = ChunkPosition(0xF, -1).plusZ()
assertEquals(position, ChunkPosition(0xF, 0))
}
@Test
fun `correct plus 2 z`() {
val position = ChunkPosition(0xF, 2)

View File

@ -85,6 +85,12 @@ class InChunkPositionTest {
assertEquals(position.plusY().y, 3)
}
@Test
fun `correct plus negative y`() {
val position = InChunkPosition(0xF, -1, 0xF).plusY()
assertEquals(position, InChunkPosition(0xF, 0, 0xF))
}
@Test
fun `correct plus 2 y`() {
val position = InChunkPosition(0xF, 2, 0xF)

View File

@ -66,6 +66,12 @@ class SectionPositionTest {
assertEquals(position.plusX().x, 3)
}
@Test
fun `correct plus negative x`() {
val position = SectionPosition(-1, 0xF, 0xF).plusX()
assertEquals(position, SectionPosition(0, 0xF, 0xF))
}
@Test
fun `correct plus 2 x`() {
val position = SectionPosition(2, 0xF, 0xF)
@ -108,6 +114,12 @@ class SectionPositionTest {
assertEquals(position.plusY().y, 3)
}
@Test
fun `correct plus negative y`() {
val position = SectionPosition(0xF, -1, 0xF).plusY()
assertEquals(position, SectionPosition(0xF, 0, 0xF))
}
@Test
fun `correct plus 2 y`() {
val position = SectionPosition(0xF, 2, 0xF)
@ -144,13 +156,18 @@ class SectionPositionTest {
assertEquals(position.z, -1875000)
}
@Test
fun `correct plus z`() {
val position = SectionPosition(0xF, 0xF, 2)
assertEquals(position.plusZ().z, 3)
}
@Test
fun `correct plus negative z`() {
val position = SectionPosition(0xF, 0xF, -1).plusZ()
assertEquals(position, SectionPosition(0xF, 0xF, 0))
}
@Test
fun `correct plus 2 z`() {
val position = SectionPosition(0xF, 0xF, 2)