mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2025-01-27 18:01:33 +01:00
Fixes and tests for LinkedCoordHashMap.
* Default order: order of first put (first put is first on iteration). * Fix order being done right for all cases. * Fix linking. * Override clear. * Add more tests.
This commit is contained in:
parent
1053c21e56
commit
a216a940d6
@ -9,7 +9,7 @@ import java.util.NoSuchElementException;
|
||||
* get/contains should work if the map stays unchanged.
|
||||
* <hr>
|
||||
* Linked hash map implementation of CoordMap<V>, allowing for insertion/access
|
||||
* order. Default order is the order of insertion. This implementation does not
|
||||
* order. By default entries are added to the end. This implementation does not
|
||||
* imitate the LinkedHashMap behavior [may be adapted to be similar, if
|
||||
* desired], instead methods are provided for manipulating the order at will.
|
||||
*
|
||||
@ -51,7 +51,7 @@ public class LinkedCoordHashMap<V> extends AbstractCoordHashMap<V, fr.neatmonste
|
||||
private LinkedHashEntry<V> current = null;
|
||||
private LinkedHashEntry<V> next;
|
||||
|
||||
private boolean reverse;
|
||||
private final boolean reverse;
|
||||
|
||||
protected LinkedHashIterator(LinkedCoordHashMap<V> map, boolean reverse) {
|
||||
this.map = map;
|
||||
@ -177,7 +177,11 @@ public class LinkedCoordHashMap<V> extends AbstractCoordHashMap<V, fr.neatmonste
|
||||
public V put(final int x, final int y, final int z, final V value, final MoveOrder order) {
|
||||
// TODO: Optimized.
|
||||
final V previousValue = super.put(x, y, z, value);
|
||||
if (order == MoveOrder.END) {
|
||||
if (order == MoveOrder.FRONT) {
|
||||
moveToFront(x, y, z);
|
||||
}
|
||||
else if (previousValue != null && order == MoveOrder.END) {
|
||||
// Ensure the intended order.
|
||||
moveToEnd(x, y, z);
|
||||
}
|
||||
return previousValue;
|
||||
@ -198,7 +202,8 @@ public class LinkedCoordHashMap<V> extends AbstractCoordHashMap<V, fr.neatmonste
|
||||
}
|
||||
|
||||
/**
|
||||
* Control order of iteration. Actual order depends on the accessOrder flag.
|
||||
* Control order of iteration.
|
||||
*
|
||||
* @param reversed
|
||||
* @return
|
||||
*/
|
||||
@ -209,8 +214,8 @@ public class LinkedCoordHashMap<V> extends AbstractCoordHashMap<V, fr.neatmonste
|
||||
@Override
|
||||
protected LinkedHashEntry<V> newEntry(int x, int y, int z, V value, int hash) {
|
||||
LinkedHashEntry<V> entry = new LinkedHashEntry<V>(x, y, z, value, hash);
|
||||
// Always put in first.
|
||||
setFirst(entry);
|
||||
// Always put in last.
|
||||
setLast(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -222,7 +227,8 @@ public class LinkedCoordHashMap<V> extends AbstractCoordHashMap<V, fr.neatmonste
|
||||
private void setFirst(LinkedHashEntry<V> entry) {
|
||||
if (this.firstEntry == null) {
|
||||
this.firstEntry = this.lastEntry = entry;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
entry.next = this.firstEntry;
|
||||
this.firstEntry.previous = entry;
|
||||
this.firstEntry = entry;
|
||||
@ -237,7 +243,8 @@ public class LinkedCoordHashMap<V> extends AbstractCoordHashMap<V, fr.neatmonste
|
||||
private void setLast(LinkedHashEntry<V> entry) {
|
||||
if (this.firstEntry == null) {
|
||||
this.firstEntry = this.lastEntry = entry;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
entry.previous = this.lastEntry;
|
||||
this.lastEntry.next = entry;
|
||||
this.lastEntry = entry;
|
||||
@ -247,18 +254,31 @@ public class LinkedCoordHashMap<V> extends AbstractCoordHashMap<V, fr.neatmonste
|
||||
@Override
|
||||
protected void removeEntry(LinkedHashEntry<V> entry) {
|
||||
// Just unlink.
|
||||
if (entry.previous == null) {
|
||||
if (entry == this.firstEntry) {
|
||||
this.firstEntry = entry.next;
|
||||
} else {
|
||||
if (this.firstEntry != null) {
|
||||
this.firstEntry.previous = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
entry.previous.next = entry.next;
|
||||
entry.previous = null;
|
||||
}
|
||||
if (entry.next == null) {
|
||||
if (entry == this.lastEntry) {
|
||||
this.lastEntry = entry.previous;
|
||||
} else {
|
||||
entry.next.previous = entry.previous;
|
||||
entry.next = null;
|
||||
if (this.lastEntry != null) {
|
||||
this.lastEntry.next = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
entry.next.previous = entry.previous;
|
||||
}
|
||||
entry.previous = entry.next = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
firstEntry = lastEntry = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import fr.neatmonster.nocheatplus.utilities.build.BuildParameters;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.map.CoordHashMap;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.map.CoordMap;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.map.CoordMap.Entry;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.map.LinkedCoordHashMap.MoveOrder;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.map.LinkedCoordHashMap;
|
||||
|
||||
public class TestCoordMap {
|
||||
@ -318,32 +319,165 @@ public class TestCoordMap {
|
||||
final int n = e ? 40000 : 6000; // Number of coordinates.
|
||||
final int max = 800; // Coordinate maximum.
|
||||
|
||||
// Preparecoordinates.
|
||||
int [][] coords = getUniqueRandomCoords(n, max, random);
|
||||
|
||||
LinkedCoordHashMap<Integer> map = new LinkedCoordHashMap<Integer>(1, 0.75f);
|
||||
|
||||
// Use a map with these coordinates.
|
||||
fillMap(map, coords);
|
||||
// Test if the order of iteration is correct (!).
|
||||
int i = 0;
|
||||
Iterator<Entry<Integer>> it = map.iterator(true); // New entries are put to front.
|
||||
while (it.hasNext()) {
|
||||
testNext(it, coords, i);
|
||||
i++;
|
||||
|
||||
// Initial iteration order.
|
||||
testIterationOrder(map, coords, 1);
|
||||
|
||||
// Re-put, moving to end.
|
||||
for (int i = 0; i < coords.length; i++) {
|
||||
map.put(coords[i][0], coords[i][1], coords[i][2], i, MoveOrder.END);
|
||||
testLast(map, coords[i], i);
|
||||
}
|
||||
i = coords.length - 1;
|
||||
it = map.iterator(false);
|
||||
while (it.hasNext()) {
|
||||
testNext(it, coords, i);
|
||||
i--;
|
||||
if (map.size() != coords.length) {
|
||||
fail("Map different size than coords.");
|
||||
}
|
||||
testIterationOrder(map, coords, 1);
|
||||
|
||||
// Re-put, moving to front.
|
||||
for (int i = coords.length - 1; i >= 0; i--) {
|
||||
map.put(coords[i][0], coords[i][1], coords[i][2], i, MoveOrder.FRONT);
|
||||
testFirst(map, coords[i], i);
|
||||
}
|
||||
if (map.size() != coords.length) {
|
||||
fail("Map different size than coords.");
|
||||
}
|
||||
testIterationOrder(map, coords, 1);
|
||||
|
||||
// Map.clear
|
||||
map.clear();
|
||||
if (map.size() != 0) {
|
||||
fail("Expect map size to be 0 after clear.");
|
||||
}
|
||||
if (map.iterator(false).hasNext()) {
|
||||
fail("Expect no first element on iteration after clear.");
|
||||
}
|
||||
if (map.iterator(true).hasNext()) {
|
||||
fail("Expect no last element on iteration after clear.");
|
||||
}
|
||||
|
||||
// TODO: Specific tests with iterator.remove.
|
||||
// New map with all coordinates.
|
||||
fillMap(map, coords);
|
||||
// Half the coordinates.
|
||||
int[][] halfCoords = new int[n / 2][3];
|
||||
for (int i = 0; i < n / 2; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
halfCoords[i][j] = coords[i * 2][j];
|
||||
}
|
||||
}
|
||||
// Test remove every second entry.
|
||||
for (int i = 0; i < n / 2; i++) {
|
||||
map.remove(coords[i * 2 + 1][0], coords[i * 2 + 1][1], coords[i * 2 + 1][2]);
|
||||
if (map.contains(coords[i * 2 + 1][0], coords[i * 2 + 1][1], coords[i * 2 + 1][2])) {
|
||||
fail("Expect removed entries not to be contained in the map.");
|
||||
}
|
||||
}
|
||||
if (map.size() != n / 2) {
|
||||
fail("Map size should be halfed after removing every second element (" + map.size() + " instead of " + n / 2 + ").");
|
||||
}
|
||||
testIterationOrder(map, halfCoords, 2);
|
||||
|
||||
// Test iterator.remove every second entry.
|
||||
map.clear();
|
||||
fillMap(map, coords);
|
||||
int i = 0;
|
||||
Iterator<Entry<Integer>> it = map.iterator(false);
|
||||
while (it.hasNext()) {
|
||||
Entry<Integer> entry = it.next();
|
||||
if (i % 2 == 1) {
|
||||
it.remove();
|
||||
if (map.contains(entry.getX(), entry.getY(), entry.getZ())) {
|
||||
fail("Expect entries removed by iterator not to be in the map.");
|
||||
}
|
||||
}
|
||||
i ++;
|
||||
}
|
||||
if (map.size() != n / 2) {
|
||||
fail("Map size should be halfed after removing every second element with an iterator (" + map.size() + " instead of " + n / 2 + ").");
|
||||
}
|
||||
testIterationOrder(map, halfCoords, 2);
|
||||
|
||||
|
||||
// TODO: Some random mixtures.
|
||||
|
||||
}
|
||||
|
||||
private void testNext(Iterator<Entry<Integer>> it, int[][] coords, int matchIndex) {
|
||||
private void testIterationOrder(LinkedCoordHashMap<Integer> map, int[][] coords, int multiplyId) {
|
||||
// Test if the order of iteration is correct (!).
|
||||
int i = 0;
|
||||
Iterator<Entry<Integer>> it = map.iterator(false); // New entries are put to the end.
|
||||
while (it.hasNext()) {
|
||||
testNext(it, coords, i, multiplyId);
|
||||
i++;
|
||||
}
|
||||
if (i != coords.length) {
|
||||
fail("Iterator different size than coords.");
|
||||
}
|
||||
if (i != map.size()) {
|
||||
fail("Iterator different size than map.");
|
||||
}
|
||||
if (map.size() != coords.length) {
|
||||
fail("Map different size than coords.");
|
||||
}
|
||||
i = coords.length - 1;
|
||||
it = map.iterator(true);
|
||||
while (it.hasNext()) {
|
||||
testNext(it, coords, i, multiplyId);
|
||||
i--;
|
||||
}
|
||||
if (i != -1) {
|
||||
fail("Iterator wrong size.");
|
||||
}
|
||||
if (map.size() != coords.length) {
|
||||
fail("Map different size than coords.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the last element is the expected one.
|
||||
* @param map
|
||||
* @param is
|
||||
*/
|
||||
private void testLast(LinkedCoordHashMap<Integer> map, int[] coords, int value) {
|
||||
if (map.get(coords[0], coords[1], coords[2]) != value) {
|
||||
fail("Not even in the map: " + value);
|
||||
}
|
||||
Entry<Integer> entry = map.iterator(true).next();
|
||||
if (entry.getValue() != value) {
|
||||
fail("Wrong id: " + entry.getValue() + " instead of " + value);
|
||||
}
|
||||
if (entry.getX() != coords[0] || entry.getY() != coords[1] || entry.getZ() != coords[2]) {
|
||||
fail("Coordinate mismatch on " + value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the first element is the expected one.
|
||||
* @param map
|
||||
* @param is
|
||||
*/
|
||||
private void testFirst(LinkedCoordHashMap<Integer> map, int[] coords, int value) {
|
||||
if (map.get(coords[0], coords[1], coords[2]) != value) {
|
||||
fail("Not even in the map: " + value);
|
||||
}
|
||||
Entry<Integer> entry = map.iterator().next();
|
||||
if (entry.getValue() != value) {
|
||||
fail("Wrong id: " + entry.getValue() + " instead of " + value);
|
||||
}
|
||||
if (entry.getX() != coords[0] || entry.getY() != coords[1] || entry.getZ() != coords[2]) {
|
||||
fail("Coordinate mismatch on " + value);
|
||||
}
|
||||
}
|
||||
|
||||
private void testNext(Iterator<Entry<Integer>> it, int[][] coords, int matchIndex, int multiplyId) {
|
||||
Entry<Integer> entry = it.next();
|
||||
if (entry.getValue().intValue() != matchIndex) {
|
||||
fail("Index mismatch, expect " + matchIndex + ", got instead: " + entry.getValue());
|
||||
if (entry.getValue().intValue() != matchIndex * multiplyId) {
|
||||
fail("Index vs. value mismatch, expect " + matchIndex * multiplyId + ", got instead: " + entry.getValue());
|
||||
}
|
||||
if (entry.getX() != coords[matchIndex][0] || entry.getY() != coords[matchIndex][1] || entry.getZ() != coords[matchIndex][2]) {
|
||||
// Very unlikely.
|
||||
|
Loading…
Reference in New Issue
Block a user