Add memory/CPU optimized BlockVectorSet
Which internally it uses a map of LocalBlockVectorSet
This commit is contained in:
parent
0427771b7e
commit
8fd908232e
@ -0,0 +1,184 @@
|
|||||||
|
package com.boydti.fawe.object.collection;
|
||||||
|
|
||||||
|
import com.boydti.fawe.util.MathMan;
|
||||||
|
import com.sk89q.worldedit.MutableBlockVector;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||||
|
import java.util.AbstractCollection;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The BlockVectorSet is a Memory optimized Set for storing BlockVectors
|
||||||
|
* - Internally it uses a map of Index->LocalBlockVectorSet
|
||||||
|
* - All BlockVectors must be a valid world coordinate: y=[0,255],x=[-30000000,30000000],z=[-30000000,30000000]
|
||||||
|
* - This will use ~8 bytes for every 64 BlockVectors (about 800x less than a HashSet)
|
||||||
|
*/
|
||||||
|
public class BlockVectorSet extends AbstractCollection<Vector> implements Set<Vector> {
|
||||||
|
private Int2ObjectMap<LocalBlockVectorSet> localSets = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
int size = 0;
|
||||||
|
for (Int2ObjectMap.Entry<LocalBlockVectorSet> entry : localSets.int2ObjectEntrySet()) {
|
||||||
|
size += entry.getValue().size();
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
for (Int2ObjectMap.Entry<LocalBlockVectorSet> entry : localSets.int2ObjectEntrySet()) {
|
||||||
|
if (!entry.getValue().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(int x, int y, int z) {
|
||||||
|
int pair = MathMan.pair((short) (x >> 11), (short) (z >> 11));
|
||||||
|
LocalBlockVectorSet localMap = localSets.get(pair);
|
||||||
|
return localMap.contains(x & 2047, y, z & 2047);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object o) {
|
||||||
|
if (o instanceof Vector) {
|
||||||
|
Vector v = (Vector) o;
|
||||||
|
return contains(v.getBlockX(), v.getBlockY(), v.getBlockZ());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Vector> iterator() {
|
||||||
|
final ObjectIterator<Int2ObjectMap.Entry<LocalBlockVectorSet>> entries = localSets.int2ObjectEntrySet().iterator();
|
||||||
|
if (!entries.hasNext()) {
|
||||||
|
return new ArrayList<Vector>().iterator();
|
||||||
|
}
|
||||||
|
return new Iterator<Vector>() {
|
||||||
|
Int2ObjectMap.Entry<LocalBlockVectorSet> entry = entries.next();
|
||||||
|
Iterator<Vector> entryIter = entry.getValue().iterator();
|
||||||
|
MutableBlockVector mutable = new MutableBlockVector();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
entryIter.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return entryIter.hasNext() || entries.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector next() {
|
||||||
|
while (!entryIter.hasNext()) {
|
||||||
|
if (!entries.hasNext()) {
|
||||||
|
throw new NoSuchElementException("End of iterator");
|
||||||
|
}
|
||||||
|
entry = entries.next();
|
||||||
|
entryIter = entry.getValue().iterator();
|
||||||
|
}
|
||||||
|
Vector localPos = entryIter.next();
|
||||||
|
int pair = entry.getIntKey();
|
||||||
|
int cx = MathMan.unpairX(pair);
|
||||||
|
int cz = MathMan.unpairY(pair);
|
||||||
|
return mutable.setComponents((cx << 11) + localPos.getBlockX(), localPos.getBlockY(), (cz << 11) + localPos.getBlockZ());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(Vector vector) {
|
||||||
|
return add(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean add(int x, int y, int z) {
|
||||||
|
int pair = MathMan.pair((short) (x >> 11), (short) (z >> 11));
|
||||||
|
LocalBlockVectorSet localMap = localSets.get(pair);
|
||||||
|
if (localMap == null) {
|
||||||
|
localMap = new LocalBlockVectorSet();
|
||||||
|
localMap.setOffset(1024, 1024);
|
||||||
|
localSets.put(pair, localMap);
|
||||||
|
}
|
||||||
|
return localMap.add(x & 2047, y, z & 2047);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean remove(int x, int y, int z) {
|
||||||
|
int pair = MathMan.pair((short) (x >> 11), (short) (z >> 11));
|
||||||
|
LocalBlockVectorSet localMap = localSets.get(pair);
|
||||||
|
if (localMap != null) {
|
||||||
|
if (localMap.remove(x & 2047, y, z & 2047)) {
|
||||||
|
if (localMap.isEmpty()) {
|
||||||
|
localSets.remove(pair);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object o) {
|
||||||
|
if (o instanceof Vector) {
|
||||||
|
Vector v = (Vector) o;
|
||||||
|
return remove(v.getBlockX(), v.getBlockY(), v.getBlockZ());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsAll(Collection<?> c) {
|
||||||
|
for (Object o : c) {
|
||||||
|
if (!contains(o)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addAll(Collection<? extends Vector> c) {
|
||||||
|
boolean result = false;
|
||||||
|
for (Vector v : c) {
|
||||||
|
result |= add(v);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean retainAll(Collection<?> c) {
|
||||||
|
Objects.requireNonNull(c);
|
||||||
|
boolean modified = false;
|
||||||
|
Iterator it = iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
if (!c.contains(it.next())) {
|
||||||
|
it.remove();
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeAll(Collection<?> c) {
|
||||||
|
boolean result = false;
|
||||||
|
for (Object o : c) {
|
||||||
|
result |= remove(o);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
localSets.clear();
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@ import java.util.Iterator;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The LocalBlockVectorSet is a Memory and CPU optimized set for storing BlockVectors which are all in a local region
|
* The LocalBlockVectorSet is a Memory and CPU optimized Set for storing BlockVectors which are all in a local region
|
||||||
* - All vectors must be in a 2048 * 2048 area centered around the first entry
|
* - All vectors must be in a 2048 * 2048 area centered around the first entry
|
||||||
* - This will use 8 bytes for every 64 BlockVectors (about 800x less than a HashSet)
|
* - This will use 8 bytes for every 64 BlockVectors (about 800x less than a HashSet)
|
||||||
*/
|
*/
|
||||||
@ -33,18 +33,24 @@ public class LocalBlockVectorSet implements Set<Vector> {
|
|||||||
return set.isEmpty();
|
return set.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean contains(int x, int y, int z) {
|
||||||
|
return set.get(MathMan.tripleSearchCoords(x - offsetX, y, z - offsetZ));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(Object o) {
|
public boolean contains(Object o) {
|
||||||
if (o instanceof Vector) {
|
if (o instanceof Vector) {
|
||||||
Vector v = (Vector) o;
|
Vector v = (Vector) o;
|
||||||
int x = v.getBlockX();
|
return contains(v.getBlockX(), v.getBlockY(), v.getBlockZ());
|
||||||
int y = v.getBlockY();
|
|
||||||
int z = v.getBlockZ();
|
|
||||||
return set.get(MathMan.tripleSearchCoords(x - offsetX, y, z - offsetZ));
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOffset(int x, int z) {
|
||||||
|
this.offsetX = x;
|
||||||
|
this.offsetZ = z;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Vector> iterator() {
|
public Iterator<Vector> iterator() {
|
||||||
return new Iterator<Vector>() {
|
return new Iterator<Vector>() {
|
||||||
@ -105,40 +111,55 @@ public class LocalBlockVectorSet implements Set<Vector> {
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public boolean add(int x, int y, int z) {
|
||||||
public boolean add(Vector vector) {
|
|
||||||
if (offsetX == Integer.MAX_VALUE) {
|
if (offsetX == Integer.MAX_VALUE) {
|
||||||
offsetX = vector.getBlockX();
|
offsetX = x;
|
||||||
offsetZ = vector.getBlockZ();
|
offsetZ = z;
|
||||||
}
|
}
|
||||||
int relX = vector.getBlockX() - offsetX;
|
int relX = x - offsetX;
|
||||||
int relZ = vector.getBlockZ() - offsetZ;
|
int relZ = z - offsetZ;
|
||||||
if (relX > 1023 || relX < -1024 || relZ > 1023 || relZ < -1024) {
|
if (relX > 1023 || relX < -1024 || relZ > 1023 || relZ < -1024) {
|
||||||
throw new UnsupportedOperationException("LocalVectorSet can only contain vectors within 1024 blocks (cuboid) of the first entry. ");
|
throw new UnsupportedOperationException("LocalVectorSet can only contain vectors within 1024 blocks (cuboid) of the first entry. ");
|
||||||
}
|
}
|
||||||
int index = getIndex(vector);
|
if (y < 0 || y > 256) {
|
||||||
|
throw new UnsupportedOperationException("LocalVectorSet can only contain vectors from y elem:[0,255]");
|
||||||
|
}
|
||||||
|
int index = getIndex(x, y, z);
|
||||||
boolean value = set.get(index);
|
boolean value = set.get(index);
|
||||||
set.set(index);
|
set.set(index);
|
||||||
return !value;
|
return !value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(Vector vector) {
|
||||||
|
return add(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ());
|
||||||
|
}
|
||||||
|
|
||||||
private int getIndex(Vector vector) {
|
private int getIndex(Vector vector) {
|
||||||
return MathMan.tripleSearchCoords(vector.getBlockX() - offsetX, vector.getBlockY(), vector.getBlockZ() - offsetZ);
|
return MathMan.tripleSearchCoords(vector.getBlockX() - offsetX, vector.getBlockY(), vector.getBlockZ() - offsetZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getIndex(int x, int y, int z) {
|
||||||
|
return MathMan.tripleSearchCoords(x - offsetX, y, z - offsetZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean remove(int x, int y, int z) {
|
||||||
|
int relX = x - offsetX;
|
||||||
|
int relZ = z - offsetZ;
|
||||||
|
if (relX > 1023 || relX < -1024 || relZ > 1023 || relZ < -1024) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int index = MathMan.tripleSearchCoords(relX, y, relZ);
|
||||||
|
boolean value = set.get(index);
|
||||||
|
set.clear(index);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean remove(Object o) {
|
public boolean remove(Object o) {
|
||||||
if (o instanceof Vector) {
|
if (o instanceof Vector) {
|
||||||
Vector v = (Vector) o;
|
Vector v = (Vector) o;
|
||||||
int relX = v.getBlockX() - offsetX;
|
return remove(v.getBlockX(), v.getBlockY(), v.getBlockZ());
|
||||||
int relZ = v.getBlockZ() - offsetZ;
|
|
||||||
if (relX > 1023 || relX < -1024 || relZ > 1023 || relZ < -1024) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int index = MathMan.tripleSearchCoords(relX, v.getBlockY(), relZ);
|
|
||||||
boolean value = set.get(index);
|
|
||||||
set.clear(index);
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user