Faster Cache (#23)

* Faster Cache

* Optimize Imports
This commit is contained in:
budgidiere 2020-11-22 18:28:40 -06:00 committed by GitHub
parent b90993c492
commit 177a18855c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 434 additions and 15 deletions

View File

@ -29,6 +29,7 @@ public final class ConfigUtil {
public static long dataSave; // Period of population data saving, in ticks. public static long dataSave; // Period of population data saving, in ticks.
public static boolean masterDisableCaves; public static boolean masterDisableCaves;
public static int biomeSearchRes; public static int biomeSearchRes;
public static int cacheSize;
public static void loadConfig(JavaPlugin main) { public static void loadConfig(JavaPlugin main) {
main.saveDefaultConfig(); main.saveDefaultConfig();
@ -40,6 +41,7 @@ public final class ConfigUtil {
dataSave = Duration.parse(Objects.requireNonNull(config.getString("data-save", "PT6M"))).toMillis() / 20L; dataSave = Duration.parse(Objects.requireNonNull(config.getString("data-save", "PT6M"))).toMillis() / 20L;
masterDisableCaves = config.getBoolean("master-disable.caves", false); masterDisableCaves = config.getBoolean("master-disable.caves", false);
biomeSearchRes = config.getInt("biome-search-resolution", 4); biomeSearchRes = config.getInt("biome-search-resolution", 4);
cacheSize = config.getInt("cache-size", 512);
if(config.getBoolean("dump-default", true)) { if(config.getBoolean("dump-default", true)) {
try(JarFile jar = new JarFile(new File(Terra.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) { try(JarFile jar = new JarFile(new File(Terra.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) {

View File

@ -15,7 +15,13 @@ import org.polydev.gaea.math.Range;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
public class CarverConfig extends TerraConfig { public class CarverConfig extends TerraConfig {
private final UserDefinedCarver carver; private final UserDefinedCarver carver;

View File

@ -1,12 +1,12 @@
package com.dfsek.terra.math; package com.dfsek.terra.math;
import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.generation.config.NoiseBuilder; import com.dfsek.terra.generation.config.NoiseBuilder;
import com.dfsek.terra.util.hash.HashMapDoubleDouble;
import org.polydev.gaea.math.FastNoiseLite; import org.polydev.gaea.math.FastNoiseLite;
import parsii.eval.Expression; import parsii.eval.Expression;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
public class NoiseFunction2 implements NoiseFunction { public class NoiseFunction2 implements NoiseFunction {
private final FastNoiseLite gen; private final FastNoiseLite gen;
@ -23,7 +23,7 @@ public class NoiseFunction2 implements NoiseFunction {
@Override @Override
public double eval(List<Expression> list) { public double eval(List<Expression> list) {
return cache.get(gen, (int) list.get(0).evaluate(), (int) list.get(1).evaluate()); return cache.get(gen, list.get(0).evaluate(), list.get(1).evaluate());
} }
/** /**
@ -41,20 +41,22 @@ public class NoiseFunction2 implements NoiseFunction {
return true; return true;
} }
private static class Cache extends LinkedHashMap<Long, Double> { private static class Cache extends HashMapDoubleDouble {
private static final long serialVersionUID = 8915092734723467010L; private static final long serialVersionUID = 8915092734723467010L;
private final int cacheSize = ConfigUtil.cacheSize;
public double get(FastNoiseLite noise, int x, int z) { public double get(FastNoiseLite noise, double x, double z) {
long key = (long) x << 32 | z & 0xFFFFFFFFL; double xx = x >= 0 ? x * 2 : x * -2 - 1;
double zz = z >= 0 ? z * 2 : z * -2 - 1;
return computeIfAbsent(key, k -> noise.getNoise(x, z)); double key = (xx >= zz) ? (xx * xx + xx + zz) : (zz * zz + xx);
double value = this.get(key);
if (this.size() > cacheSize) { this.clear(); }
return (value == 4.9E-324D ? addAndReturn(noise.getNoise(x, z), key) : value);
} }
private double addAndReturn(double value, double key) {
@Override this.put(key, value);
protected boolean removeEldestEntry(Map.Entry<Long, Double> eldest) { return value;
int maxSize = 512;
return size() > maxSize;
} }
} }
} }

View File

@ -0,0 +1,118 @@
/*
Copyright 2009 Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
retains certain rights in this software.
BSD Open Source License.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Sandia National Laboratories nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
package com.dfsek.terra.util.hash;
import java.io.Serializable;
public abstract class HashIntrinsic implements Serializable {
private static final long serialVersionUID = 8058099372006904458L;
protected static final int DEFAULT_INITIAL_CAPACITY = 16;
protected static final int MAXIMUM_CAPACITY = 1073741824;
protected static final float DEFAULT_LOAD_FACTOR = 0.75F;
protected int size;
protected int threshold;
protected float loadFactor;
protected int capMinus1;
public static final int FLOAT_EXP_BIT_MASK = 2139095040;
public static final int FLOAT_SIGNIF_BIT_MASK = 8388607;
public static final long DOUBLE_EXP_BIT_MASK = 9218868437227405312L;
public static final long DOUBLE_SIGNIF_BIT_MASK = 4503599627370495L;
protected HashIntrinsic(int initialCapacity, float loadFactor) {
if (initialCapacity <= 0) {
throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
} else if (!(loadFactor <= 0.0F) && !Float.isNaN(loadFactor)) {
if (initialCapacity > 1073741824) {
initialCapacity = 1073741824;
}
int capacity;
for(capacity = 1; capacity < initialCapacity; capacity <<= 1) {
}
this.capMinus1 = capacity - 1;
this.loadFactor = loadFactor;
this.threshold = (int)((float)capacity * loadFactor);
} else {
throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
}
}
protected static int hashCodeLong(long value) {
return (int)(value ^ value >>> 32);
}
protected static int hashCodeFloat(float value) {
return floatToIntBits(value);
}
protected static int hashCodeDouble(double value) {
long bits = doubleToLongBits(value);
return (int)(bits ^ bits >>> 32);
}
public static int floatToIntBits(float value) {
int result = Float.floatToRawIntBits(value);
if ((result & 2139095040) == 2139095040 && (result & 8388607) != 0) {
result = 2143289344;
}
return result;
}
public static long doubleToLongBits(double value) {
long result = Double.doubleToRawLongBits(value);
if ((result & 9218868437227405312L) == 9218868437227405312L && (result & 4503599627370495L) != 0L) {
result = 9221120237041090560L;
}
return result;
}
protected static int tableIndex(int hc, int lm1) {
hc ^= hc >>> 20 ^ hc >>> 12;
hc ^= hc >>> 7 ^ hc >>> 4;
return hc & lm1;
}
public int size() {
return this.size;
}
public boolean isEmpty() {
return this.size == 0;
}
public abstract void clear();
}

View File

@ -0,0 +1,291 @@
/*
Copyright 2009 Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
retains certain rights in this software.
BSD Open Source License.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Sandia National Laboratories nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
package com.dfsek.terra.util.hash;
import java.io.Serializable;
import java.util.NoSuchElementException;
public class HashMapDoubleDouble extends HashIntrinsic {
private static final long serialVersionUID = 2109458761298324234L;
private HashMapDoubleDouble.Entry[] table;
public HashMapDoubleDouble(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
this.table = this.createTable(this.capMinus1 + 1);
}
public HashMapDoubleDouble(int initialCapacity) {
this(initialCapacity, 0.75F);
}
public HashMapDoubleDouble() {
this(16, 0.75F);
}
public final boolean contains(double key) {
int i = tableIndex(hashCodeDouble(key), this.capMinus1);
for(HashMapDoubleDouble.Entry e = this.table[i]; e != null; e = e.next) {
if (e.key == key) {
return true;
}
}
return false;
}
public boolean containsValue(double value) {
for(int i = 0; i < this.table.length; ++i) {
for(HashMapDoubleDouble.Entry e = this.table[i]; e != null; e = e.next) {
if (value == e.value) {
return true;
}
}
}
return false;
}
public double get(double key) {
int i = tableIndex(hashCodeDouble(key), this.capMinus1);
for(HashMapDoubleDouble.Entry e = this.table[i]; e != null; e = e.next) {
if (key == e.key) {
return e.value;
}
}
return 4.9E-324D;
}
public HashMapDoubleDouble.Entry getEntry(double key) {
int i = tableIndex(hashCodeDouble(key), this.capMinus1);
for(HashMapDoubleDouble.Entry e = this.table[i]; e != null; e = e.next) {
if (key == e.key) {
return e;
}
}
return null;
}
public double put(double key, double value) {
int i = tableIndex(hashCodeDouble(key), this.capMinus1);
for(HashMapDoubleDouble.Entry e = this.table[i]; e != null; e = e.next) {
if (key == e.key) {
double oldValue = e.value;
e.value = value;
return oldValue;
}
}
this.addEntry(key, value, i);
return 4.9E-324D;
}
private void addEntry(double key, double value, int index) {
HashMapDoubleDouble.Entry e = this.table[index];
this.table[index] = new HashMapDoubleDouble.Entry(key, value, e);
if (this.size++ >= this.threshold) {
this.resize(2 * this.table.length);
}
}
public void resize(int newCapacity) {
int oldCapacity = this.table.length;
if (oldCapacity == 1073741824) {
this.threshold = 2147483647;
} else {
HashMapDoubleDouble.Entry[] newTable = this.createTable(newCapacity);
this.capMinus1 = newCapacity - 1;
this.transfer(newTable);
this.table = newTable;
this.threshold = (int)((float)newCapacity * this.loadFactor);
}
}
private void transfer(HashMapDoubleDouble.Entry[] newTable) {
for(int j = 0; j < this.table.length; ++j) {
HashMapDoubleDouble.Entry e = this.table[j];
if (e != null) {
this.table[j] = null;
HashMapDoubleDouble.Entry next;
do {
next = e.next;
int i = tableIndex(hashCodeDouble(e.key), this.capMinus1);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while(next != null);
}
}
}
public final HashMapDoubleDouble.Entry remove(double key) {
int i = tableIndex(hashCodeDouble(key), this.capMinus1);
HashMapDoubleDouble.Entry prev = this.table[i];
HashMapDoubleDouble.Entry e;
HashMapDoubleDouble.Entry next;
for(e = prev; e != null; e = next) {
next = e.next;
if (key == e.key) {
--this.size;
if (prev == e) {
this.table[i] = next;
} else {
prev.next = next;
}
return e;
}
prev = e;
}
return e;
}
public void clear() {
for(int i = 0; i < this.table.length; ++i) {
this.table[i] = null;
}
this.size = 0;
}
private HashMapDoubleDouble.Entry[] createTable(int capacity) {
return new HashMapDoubleDouble.Entry[capacity];
}
public long memoryEstimate(int ptrsize) {
return (long)ptrsize * (long)(this.capMinus1 + this.size + 1) + (long)(this.size * 64 / 4);
}
public HashMapDoubleDouble.Iterator iterator() {
return new HashMapDoubleDouble.Iterator();
}
public class Iterator {
HashMapDoubleDouble.Entry next;
int index;
HashMapDoubleDouble.Entry current;
Iterator() {
if (HashMapDoubleDouble.this.size > 0) {
while(this.index < HashMapDoubleDouble.this.table.length && (this.next = HashMapDoubleDouble.this.table[this.index++]) == null) {
}
}
}
public final boolean hasNext() {
return this.next != null;
}
public HashMapDoubleDouble.Entry nextEntry() {
HashMapDoubleDouble.Entry e = this.next;
if (e == null) {
throw new NoSuchElementException();
} else {
if ((this.next = e.next) == null) {
while(this.index < HashMapDoubleDouble.this.table.length && (this.next = HashMapDoubleDouble.this.table[this.index++]) == null) {
}
}
this.current = e;
return e;
}
}
public double next() {
return this.nextEntry().value;
}
public void remove() {
if (this.current == null) {
throw new IllegalStateException();
} else {
double k = this.current.key;
this.current = null;
HashMapDoubleDouble.this.remove(k);
}
}
}
public static class Entry implements Serializable {
private final double key;
private double value;
private HashMapDoubleDouble.Entry next;
private static final long serialVersionUID = 7972173983741231238L;
public Entry(double key, double val, HashMapDoubleDouble.Entry n) {
this.key = key;
this.value = val;
this.next = n;
}
public final double getKey() {
return this.key;
}
public final double getValue() {
return this.value;
}
public final double setValue(double newValue) {
double oldValue = this.value;
this.value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
HashMapDoubleDouble.Entry e = (HashMapDoubleDouble.Entry)o;
return this.key == e.key && this.value == e.value;
}
public final String toString() {
return this.key + " = " + this.value;
}
public final int hashCode() {
return hashCodeDouble(key) + hashCodeDouble(value);
}
}
}

View File

@ -13,7 +13,6 @@ import org.bukkit.block.data.Rotatable;
import org.bukkit.block.data.type.RedstoneWire; import org.bukkit.block.data.type.RedstoneWire;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
public final class RotationUtil { public final class RotationUtil {

View File

@ -4,5 +4,6 @@ language: "en_us"
fail-type: SHUTDOWN fail-type: SHUTDOWN
dump-default: true dump-default: true
biome-search-resolution: 4 biome-search-resolution: 4
cache-size: 512
master-disable: master-disable:
caves: false caves: false