Remove BlockPosSet since it is not used, twice as slow as regular tree sets and practically dont give much memory savings

This commit is contained in:
DBotThePony 2025-03-26 16:00:41 +07:00
parent 7ca0ba1ce5
commit a03c2d5eb4
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 0 additions and 298 deletions

View File

@ -1,207 +0,0 @@
package ru.dbotthepony.mc.otm.core.collect
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectRBTreeMap
import it.unimi.dsi.fastutil.objects.ObjectIterators
import net.minecraft.core.BlockPos
import net.minecraft.core.SectionPos
import net.minecraft.world.level.ChunkPos
import ru.dbotthepony.kommons.collect.iterateSetBits
import java.util.BitSet
import java.util.Collections
class BlockPosSet : MutableSet<BlockPos> {
private class Segment {
val bits = BitSet(16 * 16 * 16)
private fun pos2index(pos: BlockPos): Int {
val x = pos.x.and(15)
val z = pos.z.and(15) shl 4
val y = pos.y.and(15) shl 8
return x or y or z
}
private fun index2pos(index: Int, gX: Int, gY: Int, gZ: Int): BlockPos {
val x = index.and(15) + gX
val z = index.ushr(4).and(15) + gZ
val y = index.ushr(8).and(15) + gY
return BlockPos(x, y, z)
}
operator fun contains(pos: BlockPos): Boolean {
return bits[pos2index(pos)]
}
fun add(pos: BlockPos): Boolean {
val index = pos2index(pos)
if (bits[index])
return false
bits[index] = true
return true
}
fun remove(pos: BlockPos): Boolean {
val index = pos2index(pos)
if (!bits[index])
return false
bits[index] = false
return true
}
fun iterator(gX: Int, gY: Int, gZ: Int): MutableIterator<BlockPos> {
return object : MutableIterator<BlockPos> {
private val iterator = bits.iterateSetBits(4096)
private var last = -1
override fun hasNext(): Boolean {
return iterator.hasNext()
}
override fun next(): BlockPos {
last = iterator.nextInt()
return index2pos(last, gX, gY, gZ)
}
override fun remove() {
if (last == -1)
throw NoSuchElementException()
bits[last] = false
last = -1
}
}
}
val isEmpty: Boolean
get() = bits.isEmpty
val size: Int
get() = bits.cardinality()
}
private val segments = Object2ObjectRBTreeMap<SectionPos, Segment>(Vec3iHashStrategy)
fun subset(pos: ChunkPos): Set<BlockPos> {
val result = BlockPosSet()
for (key in segments.keys.iterator(SectionPos.of(pos.x, Int.MIN_VALUE, pos.z))) {
if (key.x != pos.x || key.z != pos.z) break
result.segments[key] = segments[key]
}
return Collections.unmodifiableSet(result)
}
override fun add(element: BlockPos): Boolean {
return segments.computeIfAbsent(SectionPos.of(element), Object2ObjectFunction { Segment() }).add(element)
}
override val size: Int
get() = segments.values.sumOf { it.size }
override fun addAll(elements: Collection<BlockPos>): Boolean {
var any = false
elements.forEach { any = add(it) || any }
return any
}
override fun clear() {
segments.clear()
}
override fun contains(element: BlockPos): Boolean {
return segments[SectionPos.of(element)]?.contains(element) == true
}
override fun containsAll(elements: Collection<BlockPos>): Boolean {
return elements.all { contains(it) }
}
override fun isEmpty(): Boolean {
var any = true
segments.entries.removeIf { (_, s) ->
any = any && s.isEmpty
s.isEmpty
}
return any
}
override fun iterator(): MutableIterator<BlockPos> {
return object : MutableIterator<BlockPos> {
private val iterator = segments.entries.iterator()
private var current: MutableIterator<BlockPos> = ObjectIterators.emptyIterator()
private var last = current
private var foundNext = false
private fun findNext() {
if (!foundNext) {
foundNext = true
while (!current.hasNext() && iterator.hasNext()) {
val (pos, itr) = iterator.next()
current = itr.iterator(pos.x shl 4, pos.y shl 4, pos.z shl 4)
}
}
}
override fun hasNext(): Boolean {
findNext()
return current.hasNext()
}
override fun next(): BlockPos {
findNext()
last = current
foundNext = false
val blockPos = current.next()
return blockPos
}
override fun remove() {
last.remove()
}
}
}
override fun remove(element: BlockPos): Boolean {
val index = SectionPos.of(element)
val segment = segments[index] ?: return false
if (segment.remove(element)) {
if (segment.isEmpty)
segments.remove(index)
return true
}
return false
}
override fun removeAll(elements: Collection<BlockPos>): Boolean {
var any = false
elements.forEach { any = remove(it) || any }
return any
}
override fun retainAll(elements: Collection<BlockPos>): Boolean {
return removeIf { it !in elements }
}
override fun equals(other: Any?): Boolean {
return this === other || other is Set<*> && other.size == size && other.containsAll(this)
}
override fun hashCode(): Int {
return segments.hashCode()
}
override fun toString(): String {
return "BlockPosSet[${joinToString(", ")}]"
}
}

View File

@ -1,91 +0,0 @@
package ru.dbotthepony.mc.otm.tests
import it.unimi.dsi.fastutil.objects.ObjectArraySet
import net.minecraft.core.BlockPos
import net.minecraft.core.SectionPos
import net.minecraft.world.level.ChunkPos
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import ru.dbotthepony.mc.otm.core.collect.BlockPosSet
import ru.dbotthepony.mc.otm.core.util.GJRAND64RandomSource
import java.util.stream.Collectors
object BlockPosSetTests {
@Test
@DisplayName("BlockPosSet additions")
fun add() {
val rand = GJRAND64RandomSource(43752304058048234L, -29394036784594328L)
val positions = ObjectArraySet<BlockPos>()
for (i in 0 until 1000) {
val x = rand.nextInt(-200, 200)
val y = rand.nextInt(-200, 200)
val z = rand.nextInt(-200, 200)
positions.add(BlockPos(x, y, z))
}
val result = BlockPosSet()
result.addAll(positions)
Assertions.assertEquals(positions, result)
Assertions.assertEquals(positions, ObjectArraySet(result))
run {
val expected = positions.stream().filter { SectionPos.blockToSectionCoord(it.x) == 0 && SectionPos.blockToSectionCoord(it.z) == 0 }.collect(Collectors.toCollection(::ObjectArraySet))
val actual = result.subset(ChunkPos.ZERO)
Assertions.assertEquals(expected, actual)
Assertions.assertEquals(expected, ObjectArraySet(actual))
}
run {
val expected = positions.stream().filter { SectionPos.blockToSectionCoord(it.x) == 0 && SectionPos.blockToSectionCoord(it.z) == 1 }.collect(Collectors.toCollection(::ObjectArraySet))
val actual = result.subset(ChunkPos(0, 1))
Assertions.assertEquals(expected, actual)
Assertions.assertEquals(expected, ObjectArraySet(actual))
}
run {
val expected = positions.stream().filter { SectionPos.blockToSectionCoord(it.x) == 0 && SectionPos.blockToSectionCoord(it.z) == -1 }.collect(Collectors.toCollection(::ObjectArraySet))
val actual = result.subset(ChunkPos(0, -1))
Assertions.assertEquals(expected, actual)
Assertions.assertEquals(expected, ObjectArraySet(actual))
}
run {
val expected = positions.stream().filter { SectionPos.blockToSectionCoord(it.x) == 1 && SectionPos.blockToSectionCoord(it.z) == 0 }.collect(Collectors.toCollection(::ObjectArraySet))
val actual = result.subset(ChunkPos(1, 0))
Assertions.assertEquals(expected, actual)
Assertions.assertEquals(expected, ObjectArraySet(actual))
}
run {
val expected = positions.stream().filter { SectionPos.blockToSectionCoord(it.x) == -1 && SectionPos.blockToSectionCoord(it.z) == 0 }.collect(Collectors.toCollection(::ObjectArraySet))
val actual = result.subset(ChunkPos(-1, 0))
Assertions.assertEquals(expected, actual)
Assertions.assertEquals(expected, ObjectArraySet(actual))
}
run {
val expected = positions.stream().filter { SectionPos.blockToSectionCoord(it.x) == 1 && SectionPos.blockToSectionCoord(it.z) == 1 }.collect(Collectors.toCollection(::ObjectArraySet))
val actual = result.subset(ChunkPos(1, 1))
Assertions.assertEquals(expected, actual)
Assertions.assertEquals(expected, ObjectArraySet(actual))
}
run {
val expected = positions.stream().filter { SectionPos.blockToSectionCoord(it.x) == -1 && SectionPos.blockToSectionCoord(it.z) == 1 }.collect(Collectors.toCollection(::ObjectArraySet))
val actual = result.subset(ChunkPos(-1, 1))
Assertions.assertEquals(expected, actual)
Assertions.assertEquals(expected, ObjectArraySet(actual))
}
}
}