From a03c2d5eb4a3cbf0a062b7642551b7ed94298d16 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 16:00:41 +0700 Subject: [PATCH] Remove BlockPosSet since it is not used, twice as slow as regular tree sets and practically dont give much memory savings --- .../mc/otm/core/collect/BlockPosSet.kt | 207 ------------------ .../mc/otm/tests/BlockPosSetTests.kt | 91 -------- 2 files changed, 298 deletions(-) delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/BlockPosSet.kt delete mode 100644 src/test/kotlin/ru/dbotthepony/mc/otm/tests/BlockPosSetTests.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/BlockPosSet.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/BlockPosSet.kt deleted file mode 100644 index a4a24cc32..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/BlockPosSet.kt +++ /dev/null @@ -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 { - 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 { - return object : MutableIterator { - 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(Vec3iHashStrategy) - - fun subset(pos: ChunkPos): Set { - 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): 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): 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 { - return object : MutableIterator { - private val iterator = segments.entries.iterator() - private var current: MutableIterator = 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): Boolean { - var any = false - elements.forEach { any = remove(it) || any } - return any - } - - override fun retainAll(elements: Collection): 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(", ")}]" - } -} diff --git a/src/test/kotlin/ru/dbotthepony/mc/otm/tests/BlockPosSetTests.kt b/src/test/kotlin/ru/dbotthepony/mc/otm/tests/BlockPosSetTests.kt deleted file mode 100644 index a67f2f102..000000000 --- a/src/test/kotlin/ru/dbotthepony/mc/otm/tests/BlockPosSetTests.kt +++ /dev/null @@ -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() - - 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)) - } - } -}