feat[map]: add primitive int-long tree map

This commit is contained in:
godotg committed 2023-03-26 11:53:30 +08:00
1 parent 3e26ce4a77
commit 626e96f0f3
4 files changed
+1275

No files matched your search

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.net.packet.common;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.zfoo.protocol.IPacket;
import java.util.Comparator;
/**
* @author godotg
* @version 3.0
*/
public class PairIntLong implements IPacket {
public static final short PROTOCOL_ID = 110;
@JsonSerialize(using = ToStringSerializer.class)
private int key;
@JsonSerialize(using = ToStringSerializer.class)
private long value;
public static PairIntLong valueOf(int key, long value) {
var pair = new PairIntLong();
pair.key = key;
pair.value = value;
return pair;
}
@Override
public short protocolId() {
return PROTOCOL_ID;
}
public int getKey() {
return key;
}
public void setKey(int key) {
this.key = key;
}
public long getValue() {
return value;
}
public void setValue(long value) {
this.value = value;
}
}
@@ -0,0 +1,788 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.net.util;
import com.zfoo.net.packet.common.PairIntLong;
import java.util.Arrays;
/**
* @author godotg
* @version 3.0
*/
public class TreeMapIntLong {
private static final int DEFAULT_CAPACITY = 10;
private static final double ENLARGE_SCALE = 2.0;
private static final boolean BLACK = false;
private static final boolean RED = true;
private static final int NULL = 0;
private static final int DEFAULT_NULL_KEY = (new int[1])[0];
private static final long DEFAULT_NULL_VALUE = (new long[1])[0];
// Arrays are 1-indexed. Index 0 is a null node.
private int[] keys;
private long[] values;
private int[] left;
private int[] right;
private int[] p;
private boolean[] color;
private int size;
private int root;
private boolean returnedNull;
public TreeMapIntLong() {
this(DEFAULT_CAPACITY);
}
public TreeMapIntLong(int capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("Capacity must be non-negative");
}
capacity++;
keys = new int[capacity];
values = new long[capacity];
left = new int[capacity];
right = new int[capacity];
p = new int[capacity];
color = new boolean[capacity];
color[NULL] = BLACK;
size = 0;
root = NULL;
returnedNull = false;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public boolean containsKey(int key) {
int x = root;
while (x != NULL) {
if (key < keys[x]) {
x = left[x];
} else if (key > keys[x]) {
x = right[x];
} else {
return true;
}
}
return false;
}
public long get(int key) {
int x = root;
while (x != NULL) {
if (key < keys[x]) {
x = left[x];
} else if (key > keys[x]) {
x = right[x];
} else {
returnedNull = false;
return values[x];
}
}
returnedNull = true;
return DEFAULT_NULL_VALUE;
}
public long put(int key, long value) {
int y = NULL;
int x = root;
while (x != NULL) {
//noinspection SuspiciousNameCombination
y = x;
if (key < keys[x]) {
x = left[x];
} else if (key > keys[x]) {
x = right[x];
} else {
final long oldValue = values[x];
values[x] = value;
returnedNull = false;
return oldValue;
}
}
if (size == color.length - 1) {
enlarge();
}
int z = ++size;
keys[z] = key;
values[z] = value;
p[z] = y;
if (y == NULL) {
root = z;
} else {
if (key < keys[y]) {
left[y] = z;
} else {
right[y] = z;
}
}
left[z] = NULL;
right[z] = NULL;
color[z] = RED;
fixAfterAdd(z);
returnedNull = true;
return DEFAULT_NULL_VALUE;
}
public long remove(int key) {
int z = root;
while (z != NULL) {
if (key < keys[z]) {
z = left[z];
} else if (key > keys[z]) {
z = right[z];
} else {
final long removedValue = values[z];
removeNode(z);
returnedNull = false;
return removedValue;
}
}
returnedNull = true;
return DEFAULT_NULL_VALUE;
}
private void removeNode(int z) {
int y = (left[z] == NULL || right[z] == NULL) ? z : successorNode(z);
int x = (left[y] != NULL) ? left[y] : right[y];
p[x] = p[y];
if (p[y] == NULL) {
root = x;
} else {
if (y == left[p[y]]) {
left[p[y]] = x;
} else {
right[p[y]] = x;
}
}
if (y != z) {
keys[z] = keys[y];
values[z] = values[y];
}
//noinspection PointlessBooleanExpression
if (color[y] == BLACK) {
fixAfterRemove(x);
}
// Swap with last
if (y != size) {
// copy fields
keys[y] = keys[size];
values[y] = values[size];
left[y] = left[size];
right[y] = right[size];
p[y] = p[size];
color[y] = color[size];
// fix the children's parents
p[left[size]] = y;
p[right[size]] = y;
// fix one of the parent's children
if (left[p[size]] == size) {
left[p[size]] = y;
} else {
right[p[size]] = y;
}
// fix root
if (root == size) {
root = y;
}
}
size--;
}
private int successorNode(int x) {
if (right[x] != NULL) {
x = right[x];
while (left[x] != NULL) {
x = left[x];
}
return x;
} else {
int y = p[x];
while (y != NULL && x == right[y]) {
//noinspection SuspiciousNameCombination
x = y;
y = p[y];
}
return y;
}
}
private void fixAfterAdd(int z) {
while (color[p[z]] == RED) {
if (p[z] == left[p[p[z]]]) {
int y = right[p[p[z]]];
if (color[y] == RED) {
color[p[z]] = BLACK;
color[y] = BLACK;
color[p[p[z]]] = RED;
z = p[p[z]];
} else {
if (z == right[p[z]]) {
z = p[z];
rotateLeft(z);
}
color[p[z]] = BLACK;
color[p[p[z]]] = RED;
rotateRight(p[p[z]]);
}
} else {
int y = left[p[p[z]]];
if (color[y] == RED) {
color[p[z]] = BLACK;
color[y] = BLACK;
color[p[p[z]]] = RED;
z = p[p[z]];
} else {
if (z == left[p[z]]) {
z = p[z];
rotateRight(z);
}
color[p[z]] = BLACK;
color[p[p[z]]] = RED;
rotateLeft(p[p[z]]);
}
}
}
color[root] = BLACK;
}
private void fixAfterRemove(int x) {
while (x != root && color[x] == BLACK) {
if (x == left[p[x]]) {
int w = right[p[x]];
if (color[w] == RED) {
color[w] = BLACK;
color[p[x]] = RED;
rotateLeft(p[x]);
w = right[p[x]];
}
if (color[left[w]] == BLACK && color[right[w]] == BLACK) {
color[w] = RED;
x = p[x];
} else {
if (color[right[w]] == BLACK) {
color[left[w]] = BLACK;
color[w] = RED;
rotateRight(w);
w = right[p[x]];
}
color[w] = color[p[x]];
color[p[x]] = BLACK;
color[right[w]] = BLACK;
rotateLeft(p[x]);
x = root;
}
} else {
int w = left[p[x]];
if (color[w] == RED) {
color[w] = BLACK;
color[p[x]] = RED;
rotateRight(p[x]);
w = left[p[x]];
}
if (color[left[w]] == BLACK && color[right[w]] == BLACK) {
color[w] = RED;
x = p[x];
} else {
if (color[left[w]] == BLACK) {
color[right[w]] = BLACK;
color[w] = RED;
rotateLeft(w);
w = left[p[x]];
}
color[w] = color[p[x]];
color[p[x]] = BLACK;
color[left[w]] = BLACK;
rotateRight(p[x]);
x = root;
}
}
}
color[x] = BLACK;
}
private void rotateLeft(int x) {
int y = right[x];
right[x] = left[y];
if (left[y] != NULL) {
p[left[y]] = x;
}
p[y] = p[x];
if (p[x] == NULL) {
root = y;
} else {
if (x == left[p[x]]) {
left[p[x]] = y;
} else {
right[p[x]] = y;
}
}
left[y] = x;
p[x] = y;
}
private void rotateRight(int x) {
int y = left[x];
left[x] = right[y];
if (right[y] != NULL) {
p[right[y]] = x;
}
p[y] = p[x];
if (p[x] == NULL) {
root = y;
} else {
if (x == right[p[x]]) {
right[p[x]] = y;
} else {
left[p[x]] = y;
}
}
right[y] = x;
p[x] = y;
}
public boolean returnedNull() {
return returnedNull;
}
public void clear() {
color[NULL] = BLACK;
size = 0;
root = NULL;
}
public int[] keys() {
int[] result = new int[size];
for (int i = 0, x = firstNode(); x != NULL; x = successorNode(x), i++) {
result[i] = keys[x];
}
return result;
}
public long[] values() {
long[] result = new long[size];
for (int i = 0, x = firstNode(); x != NULL; x = successorNode(x), i++) {
result[i] = values[x];
}
return result;
}
private void enlarge() {
int newLength = Math.max(color.length + 1, (int) (color.length * ENLARGE_SCALE));
keys = Arrays.copyOf(keys, newLength);
values = Arrays.copyOf(values, newLength);
left = Arrays.copyOf(left, newLength);
right = Arrays.copyOf(right, newLength);
p = Arrays.copyOf(p, newLength);
color = Arrays.copyOf(color, newLength);
}
private int firstNode() {
int x = root;
while (left[x] != NULL) {
x = left[x];
}
return x;
}
private int lastNode() {
int x = root;
while (right[x] != NULL) {
x = right[x];
}
return x;
}
public int getFirstKey() {
if (root == NULL) {
returnedNull = true;
return DEFAULT_NULL_KEY;
}
final int x = firstNode();
returnedNull = false;
return keys[x];
}
public int getLastKey() {
if (root == NULL) {
returnedNull = true;
return DEFAULT_NULL_KEY;
}
final int x = lastNode();
returnedNull = false;
return keys[x];
}
public PairIntLong getFirstEntry() {
if (root == NULL) {
returnedNull = true;
return null;
}
final int x = firstNode();
returnedNull = false;
return PairIntLong.valueOf(keys[x], values[x]);
}
public PairIntLong getLastEntry() {
if (root == NULL) {
returnedNull = true;
return null;
}
final int x = lastNode();
returnedNull = false;
return PairIntLong.valueOf(keys[x], values[x]);
}
public int floorKey(int key) {
int x = root;
while (x != NULL) {
if (key > keys[x]) {
if (right[x] != NULL) {
x = right[x];
} else {
returnedNull = false;
return keys[x];
}
} else if (key < keys[x]) {
if (left[x] != NULL) {
x = left[x];
} else {
int y = p[x];
while (y != NULL && x == left[y]) {
//noinspection SuspiciousNameCombination
x = y;
y = p[y];
}
if (y == NULL) {
returnedNull = true;
return DEFAULT_NULL_KEY;
} else {
returnedNull = false;
return keys[y];
}
}
} else {
returnedNull = false;
return keys[x];
}
}
returnedNull = true;
return DEFAULT_NULL_KEY;
}
public int ceilingKey(int key) {
int x = root;
while (x != NULL) {
if (key < keys[x]) {
if (left[x] != NULL) {
x = left[x];
} else {
returnedNull = false;
return keys[x];
}
} else if (key > keys[x]) {
if (right[x] != NULL) {
x = right[x];
} else {
int y = p[x];
while (y != NULL && x == right[y]) {
//noinspection SuspiciousNameCombination
x = y;
y = p[y];
}
if (y == NULL) {
returnedNull = true;
return DEFAULT_NULL_KEY;
} else {
returnedNull = false;
return keys[y];
}
}
} else {
returnedNull = false;
return keys[x];
}
}
returnedNull = true;
return DEFAULT_NULL_KEY;
}
public int lowerKey(int key) {
int x = root;
while (x != NULL) {
if (key > keys[x]) {
if (right[x] != NULL) {
x = right[x];
} else {
returnedNull = false;
return keys[x];
}
} else {
if (left[x] != NULL) {
x = left[x];
} else {
int y = p[x];
while (y != NULL && x == left[y]) {
//noinspection SuspiciousNameCombination
x = y;
y = p[y];
}
if (y == NULL) {
returnedNull = true;
return DEFAULT_NULL_KEY;
} else {
returnedNull = false;
return keys[y];
}
}
}
}
returnedNull = true;
return DEFAULT_NULL_KEY;
}
public int higherKey(int key) {
int x = root;
while (x != NULL) {
if (key < keys[x]) {
if (left[x] != NULL) {
x = left[x];
} else {
returnedNull = false;
return keys[x];
}
} else {
if (right[x] != NULL) {
x = right[x];
} else {
int y = p[x];
while (y != NULL && x == right[y]) {
//noinspection SuspiciousNameCombination
x = y;
y = p[y];
}
if (y == NULL) {
returnedNull = true;
return DEFAULT_NULL_KEY;
} else {
returnedNull = false;
return keys[y];
}
}
}
}
returnedNull = true;
return DEFAULT_NULL_KEY;
}
public PairIntLong floorEntry(int key) {
int x = root;
while (x != NULL) {
if (key > keys[x]) {
if (right[x] != NULL) {
x = right[x];
} else {
returnedNull = false;
return PairIntLong.valueOf(keys[x], values[x]);
}
} else if (key < keys[x]) {
if (left[x] != NULL) {
x = left[x];
} else {
int y = p[x];
while (y != NULL && x == left[y]) {
//noinspection SuspiciousNameCombination
x = y;
y = p[y];
}
if (y == NULL) {
returnedNull = true;
return null;
} else {
returnedNull = false;
return PairIntLong.valueOf(keys[y], values[y]);
}
}
} else {
returnedNull = false;
return PairIntLong.valueOf(keys[x], values[x]);
}
}
returnedNull = true;
return null;
}
public PairIntLong ceilingEntry(int key) {
int x = root;
while (x != NULL) {
if (key < keys[x]) {
if (left[x] != NULL) {
x = left[x];
} else {
returnedNull = false;
return PairIntLong.valueOf(keys[x], values[x]);
}
} else if (key > keys[x]) {
if (right[x] != NULL) {
x = right[x];
} else {
int y = p[x];
while (y != NULL && x == right[y]) {
//noinspection SuspiciousNameCombination
x = y;
y = p[y];
}
if (y == NULL) {
returnedNull = true;
return null;
} else {
returnedNull = false;
return PairIntLong.valueOf(keys[y], values[y]);
}
}
} else {
returnedNull = false;
return PairIntLong.valueOf(keys[x], values[x]);
}
}
returnedNull = true;
return null;
}
public PairIntLong lowerEntry(int key) {
int x = root;
while (x != NULL) {
if (key > keys[x]) {
if (right[x] != NULL) {
x = right[x];
} else {
returnedNull = false;
return PairIntLong.valueOf(keys[x], values[x]);
}
} else {
if (left[x] != NULL) {
x = left[x];
} else {
int y = p[x];
while (y != NULL && x == left[y]) {
//noinspection SuspiciousNameCombination
x = y;
y = p[y];
}
if (y == NULL) {
returnedNull = true;
return null;
} else {
returnedNull = false;
return PairIntLong.valueOf(keys[y], values[y]);
}
}
}
}
returnedNull = true;
return null;
}
public PairIntLong higherEntry(int key) {
int x = root;
while (x != NULL) {
if (key < keys[x]) {
if (left[x] != NULL) {
x = left[x];
} else {
returnedNull = false;
return PairIntLong.valueOf(keys[x], values[x]);
}
} else {
if (right[x] != NULL) {
x = right[x];
} else {
int y = p[x];
while (y != NULL && x == right[y]) {
//noinspection SuspiciousNameCombination
x = y;
y = p[y];
}
if (y == NULL) {
returnedNull = true;
return null;
} else {
returnedNull = false;
return PairIntLong.valueOf(keys[y], values[y]);
}
}
}
}
returnedNull = true;
return null;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TreeMapIntLong that = (TreeMapIntLong) o;
if (size != that.size) {
return false;
}
for (int x = firstNode(), y = that.firstNode(); x != NULL;
//noinspection SuspiciousNameCombination
x = successorNode(x), y = that.successorNode(y)) {
if (keys[x] != that.keys[y] || values[x] != that.values[y]) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
int hash = 0;
for (int x = firstNode(); x != NULL; x = successorNode(x)) {
hash = hash ^ keys[x] ^ (int) values[x];
}
return hash;
}
}
@@ -0,0 +1,423 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.net.util;
import com.zfoo.net.packet.common.PairIntLong;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
/**
* @author godotg
* @version 3.0
*/
public class TreeMapTest {
private void testPermutation(int[] array) {
int n = array.length;
TreeMapIntLong map = new TreeMapIntLong(0);
for (int it = 0; it < 3; it++) {
Assert.assertEquals(map.size(), 0);
Assert.assertTrue(map.isEmpty());
for (int i = 0; i < n; i++) {
map.put(array[i], 2 * array[i]);
Assert.assertTrue(map.returnedNull());
Assert.assertEquals(map.size(), i + 1);
Assert.assertFalse(map.isEmpty());
}
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < n; i++) {
Assert.assertEquals(map.put(array[i], 3 * array[i]), 2 * array[i]);
Assert.assertFalse(map.returnedNull());
Assert.assertEquals(map.size(), n);
Assert.assertFalse(map.isEmpty());
}
for (int i = -1; i <= n; i++) {
if (0 <= i && i < n) {
Assert.assertTrue(map.containsKey(array[i]));
Assert.assertEquals(map.get(array[i]), 3 * array[i]);
Assert.assertFalse(map.returnedNull());
} else {
Assert.assertFalse(map.containsKey(i));
map.get(i);
Assert.assertTrue(map.returnedNull());
}
}
Assert.assertEquals(map.getFirstKey(), 0);
Assert.assertFalse(map.returnedNull());
Assert.assertEquals(map.getFirstEntry(), PairIntLong.valueOf(0, 0L));
Assert.assertFalse(map.returnedNull());
Assert.assertEquals(map.getLastKey(), n - 1);
Assert.assertFalse(map.returnedNull());
Assert.assertEquals(map.getLastEntry(), PairIntLong.valueOf(n - 1, (long) (3 * (n - 1))));
Assert.assertFalse(map.returnedNull());
for (int i = -2; i <= n + 1; i++) {
int lowerKey = map.lowerKey(i);
if (i > 0) {
Assert.assertEquals(lowerKey, Math.min(i - 1, n - 1));
Assert.assertFalse(map.returnedNull());
} else {
Assert.assertTrue(map.returnedNull());
}
int higherKey = map.higherKey(i);
if (i < n - 1) {
Assert.assertEquals(higherKey, Math.max(i + 1, 0));
Assert.assertFalse(map.returnedNull());
} else {
Assert.assertTrue(map.returnedNull());
}
int floorKey = map.floorKey(i);
if (i >= 0) {
Assert.assertEquals(floorKey, Math.min(i, n - 1));
Assert.assertFalse(map.returnedNull());
} else {
Assert.assertTrue(map.returnedNull());
}
int ceilingKey = map.ceilingKey(i);
if (i < n) {
Assert.assertEquals(ceilingKey, Math.max(i, 0));
Assert.assertFalse(map.returnedNull());
} else {
Assert.assertTrue(map.returnedNull());
}
PairIntLong lowerEntry = map.lowerEntry(i);
if (i > 0) {
Assert.assertEquals(lowerEntry, PairIntLong.valueOf(lowerKey, (long) (3 * lowerKey)));
Assert.assertFalse(map.returnedNull());
} else {
Assert.assertNull(lowerEntry);
Assert.assertTrue(map.returnedNull());
}
PairIntLong higherEntry = map.higherEntry(i);
if (i < n - 1) {
Assert.assertEquals(higherEntry, PairIntLong.valueOf(higherKey, (long) (3 * higherKey)));
Assert.assertFalse(map.returnedNull());
} else {
Assert.assertNull(higherEntry);
Assert.assertTrue(map.returnedNull());
}
PairIntLong floorEntry = map.floorEntry(i);
if (i >= 0) {
Assert.assertEquals(floorEntry, PairIntLong.valueOf(floorKey, (long) (3 * floorKey)));
Assert.assertFalse(map.returnedNull());
} else {
Assert.assertNull(floorEntry);
Assert.assertTrue(map.returnedNull());
}
PairIntLong ceilingEntry = map.ceilingEntry(i);
if (i < n) {
Assert.assertEquals(ceilingEntry, PairIntLong.valueOf(ceilingKey, (long) (3 * ceilingKey)));
Assert.assertFalse(map.returnedNull());
} else {
Assert.assertNull(ceilingEntry);
Assert.assertTrue(map.returnedNull());
}
}
int removed = 0;
for (int i = -1; i <= n; i++) {
if (0 <= i && i < n) {
Assert.assertEquals(map.remove(array[i]), 3 * array[i]);
Assert.assertFalse(map.returnedNull());
removed++;
} else {
map.remove(i);
Assert.assertTrue(map.returnedNull());
}
Assert.assertEquals(map.size(), n - removed);
}
map.clear();
}
}
private void genPermutations(int[] permutation, int left, int length) {
if (left >= length - 1) {
testPermutation(permutation);
return;
}
for (int i = left; i < length; i++) {
swap(permutation, i, left);
genPermutations(permutation, left + 1, length);
swap(permutation, i, left);
}
}
private void swap(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
private void shuffle(int[] a, Random rnd) {
int n = a.length;
for (int i = 0; i < n; i++) {
int j = i + rnd.nextInt(n - i);
swap(a, i, j);
}
}
@Test
public void testAllSmallPermutations() {
for (int length = 1; length <= 8; length++) {
int[] a = new int[length];
for (int i = 0; i < length; i++) {
a[i] = i;
}
genPermutations(a, 0, length);
}
}
@Test
public void testManyPermutationsLength100() {
Random rnd = new Random(-228);
for (int it = 0; it < 7000; it++) {
int length = 9 + rnd.nextInt(92);
int[] a = new int[length];
for (int i = 0; i < length; i++) {
a[i] = i;
}
shuffle(a, rnd);
testPermutation(a);
}
}
@Test
public void testFewPermutationsLength10000() {
Random rnd = new Random(-322);
for (int it = 0; it < 35; it++) {
int length = 9 + rnd.nextInt(9992);
int[] a = new int[length];
for (int i = 0; i < length; i++) {
a[i] = i;
}
shuffle(a, rnd);
testPermutation(a);
}
}
@Test
public void testOperationsOnEmptyMap() {
TreeMapIntLong map = new TreeMapIntLong(0);
Assert.assertTrue(map.isEmpty());
Assert.assertEquals(map.size(), 0);
for (int key = -200; key <= 200; key++) {
Assert.assertFalse(map.containsKey(key));
map.get(key);
Assert.assertTrue(map.returnedNull());
map.remove(key);
Assert.assertTrue(map.returnedNull());
map.getFirstKey();
Assert.assertTrue(map.returnedNull());
map.getLastKey();
Assert.assertTrue(map.returnedNull());
map.higherKey(key);
Assert.assertTrue(map.returnedNull());
map.lowerKey(key);
Assert.assertTrue(map.returnedNull());
map.ceilingKey(key);
Assert.assertTrue(map.returnedNull());
map.floorKey(key);
Assert.assertTrue(map.returnedNull());
Assert.assertEquals(map.higherEntry(key), null);
Assert.assertTrue(map.returnedNull());
Assert.assertEquals(map.lowerEntry(key), null);
Assert.assertTrue(map.returnedNull());
Assert.assertEquals(map.ceilingEntry(key), null);
Assert.assertTrue(map.returnedNull());
Assert.assertEquals(map.floorEntry(key), null);
Assert.assertTrue(map.returnedNull());
Assert.assertEquals(map.getFirstEntry(), null);
Assert.assertTrue(map.returnedNull());
Assert.assertEquals(map.getLastEntry(), null);
Assert.assertTrue(map.returnedNull());
}
Assert.assertArrayEquals(map.keys(), new int[0]);
Assert.assertArrayEquals(map.values(), new long[0]);
}
private void assertSortedMapMethods(TreeMapIntLong map, TreeMap<Integer, Long> javaMap, int key) {
{
Map.Entry<Integer, Long> javaEntry = javaMap.floorEntry(key);
int ezResultKey = map.floorKey(key);
if (javaEntry == null) {
Assert.assertTrue(map.returnedNull());
} else {
Assert.assertEquals(ezResultKey, (int) javaEntry.getKey());
}
PairIntLong ezResultEntry = map.floorEntry(key);
if (javaEntry == null) {
Assert.assertTrue(map.returnedNull());
Assert.assertNull(ezResultEntry);
} else {
Assert.assertEquals(ezResultEntry, PairIntLong.valueOf(javaEntry.getKey(), (long) javaEntry.getValue()));
}
}
{
Map.Entry<Integer, Long> javaEntry = javaMap.ceilingEntry(key);
int ezResultKey = map.ceilingKey(key);
if (javaEntry == null) {
Assert.assertTrue(map.returnedNull());
} else {
Assert.assertEquals(ezResultKey, (int) javaEntry.getKey());
}
PairIntLong ezResultEntry = map.ceilingEntry(key);
if (javaEntry == null) {
Assert.assertTrue(map.returnedNull());
Assert.assertNull(ezResultEntry);
} else {
Assert.assertEquals(ezResultEntry, PairIntLong.valueOf(javaEntry.getKey(), (long) javaEntry.getValue()));
}
}
{
Map.Entry<Integer, Long> javaEntry = javaMap.lowerEntry(key);
int ezResultKey = map.lowerKey(key);
if (javaEntry == null) {
Assert.assertTrue(map.returnedNull());
} else {
Assert.assertEquals(ezResultKey, (int) javaEntry.getKey());
}
PairIntLong ezResultEntry = map.lowerEntry(key);
if (javaEntry == null) {
Assert.assertTrue(map.returnedNull());
Assert.assertNull(ezResultEntry);
} else {
Assert.assertEquals(ezResultEntry, PairIntLong.valueOf(javaEntry.getKey(), (long) javaEntry.getValue()));
}
}
{
Map.Entry<Integer, Long> javaEntry = javaMap.higherEntry(key);
int ezResultKey = map.higherKey(key);
if (javaEntry == null) {
Assert.assertTrue(map.returnedNull());
} else {
Assert.assertEquals(ezResultKey, (int) javaEntry.getKey());
}
PairIntLong ezResultEntry = map.higherEntry(key);
if (javaEntry == null) {
Assert.assertTrue(map.returnedNull());
Assert.assertNull(ezResultEntry);
} else {
Assert.assertEquals(ezResultEntry, PairIntLong.valueOf(javaEntry.getKey(), (long) javaEntry.getValue()));
}
}
}
@Test
public void testSignificantMethodsOnRandomData() {
TreeMapIntLong map = new TreeMapIntLong();
TreeMap<Integer, Long> javaMap = new TreeMap<Integer, Long>();
Random rnd = new Random(~42);
for (int i = 0; i < 1000000; i++) {
Assert.assertEquals(map.size(), javaMap.size());
double prob = rnd.nextDouble();
if (prob < 0.301) {
int key = rnd.nextInt(50);
long newValue = rnd.nextInt();
Long oldValue = javaMap.put(key, newValue);
if (oldValue == null) {
map.put(key, newValue);
Assert.assertTrue(map.returnedNull());
} else {
long actualOldValue = map.put(key, newValue);
Assert.assertFalse(map.returnedNull());
Assert.assertEquals(actualOldValue, (long) oldValue);
}
} else if (prob < 0.6) {
int key = rnd.nextInt(50);
Long oldValue = javaMap.remove(key);
if (oldValue == null) {
map.remove(key);
Assert.assertTrue(map.returnedNull());
} else {
long actualOldValue = map.remove(key);
Assert.assertFalse(map.returnedNull());
Assert.assertEquals(actualOldValue, (long) oldValue);
}
} else {
int key = rnd.nextInt(20);
assertSortedMapMethods(map, javaMap, key);
}
}
}
@Test
public void testKeysValuesArrays() {
int[] keys = new int[100];
long[] values = new long[100];
for (int i = 0; i < 100; i++) {
keys[i] = i * 322 + 228;
values[i] = i * 228 + 322;
}
for (int len = 0; len <= 100; len++) {
TreeMapIntLong map = new TreeMapIntLong();
for (int i = 0; i < len; i++) {
map.put(keys[i], values[i]);
Assert.assertTrue(map.returnedNull());
}
Assert.assertArrayEquals(map.keys(), Arrays.copyOfRange(keys, 0, len));
Assert.assertArrayEquals(map.values(), Arrays.copyOfRange(values, 0, len));
}
}
@Test
public void testEqualsHashcode() {
for (int mask1 = 0; mask1 < 32; mask1++) {
for (int mask2 = 0; mask2 < 32; mask2++) {
TreeMapIntLong map1 = new TreeMapIntLong(1);
TreeMapIntLong map2 = new TreeMapIntLong(1);
for (int i = 0; i < 5; i++) {
if ((mask1 & (1 << i)) != 0) {
map1.put(1000 * i, i);
}
if ((mask2 & (1 << i)) != 0) {
map2.put(1000 * i, i);
}
}
int hashCode1 = map1.hashCode();
int hashCode2 = map2.hashCode();
if (mask1 == mask2) {
Assert.assertTrue(map1.equals(map2));
Assert.assertTrue(map2.equals(map1));
Assert.assertTrue(hashCode1 == hashCode2);
} else {
Assert.assertFalse(map1.equals(map2));
Assert.assertFalse(map2.equals(map1));
}
}
}
}
@Test
public void testCelling() {
var max = 10000;
TreeMapIntLong treeMap = new TreeMapIntLong(200);
for (int i = 0; i < max; i++) {
if (i % 2 == 0) {
treeMap.put(i, i);
}
}
for (int i = 0; i < max; i++) {
if (i % 2 != 0 && i != (max - 1)) {
Assert.assertEquals(treeMap.ceilingEntry(i).getValue(), i + 1);
}
if (i % 2 != 0) {
Assert.assertEquals(treeMap.floorEntry(i).getValue(), i - 1);
}
}
}
}
+1
View File
@@ -26,6 +26,7 @@
<protocol id="103" location="com.zfoo.net.packet.common.Ping"/>
<protocol id="104" location="com.zfoo.net.packet.common.Pong"/>
<protocol id="110" location="com.zfoo.net.packet.common.PairIntLong"/>
<protocol id="111" location="com.zfoo.net.packet.common.PairLong"/>
<protocol id="112" location="com.zfoo.net.packet.common.PairString"/>
<protocol id="113" location="com.zfoo.net.packet.common.PairLS"/>