提交 7ea4acb5 编写于 作者: V Vlad Ilyushchenko

#64: IntLong- and LongLong hash maps.

上级 a245fb52
/*******************************************************************************
* ___ _ ____ ____
* / _ \ _ _ ___ ___| |_| _ \| __ )
* | | | | | | |/ _ \/ __| __| | | | _ \
* | |_| | |_| | __/\__ \ |_| |_| | |_) |
* \__\_\\__,_|\___||___/\__|____/|____/
*
* Copyright (C) 2014-2019 Appsicle
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
package com.questdb.std;
import java.util.Arrays;
public class IntLongHashMap extends AbstractIntHashSet {
private static final int noEntryValue = -1;
private long[] values;
public IntLongHashMap() {
this(8);
}
public IntLongHashMap(int initialCapacity) {
this(initialCapacity, 0.5f);
}
private IntLongHashMap(int initialCapacity, double loadFactor) {
super(initialCapacity, loadFactor);
values = new long[keys.length];
clear();
}
public long get(int key) {
return valueAt(keyIndex(key));
}
public void put(int key, long value) {
putAt(keyIndex(key), key, value);
}
public void putAt(int index, int key, long value) {
if (index < 0) {
Unsafe.arrayPut(values, -index - 1, value);
} else {
Unsafe.arrayPut(keys, index, key);
Unsafe.arrayPut(values, index, value);
if (--free == 0) {
rehash();
}
}
}
public long valueAt(int index) {
return index < 0 ? Unsafe.arrayGet(values, -index - 1) : noEntryValue;
}
@Override
protected void erase(int index) {
Unsafe.arrayPut(keys, index, this.noEntryKeyValue);
}
@Override
protected void move(int from, int to) {
Unsafe.arrayPut(keys, to, Unsafe.arrayGet(keys, from));
Unsafe.arrayPut(values, to, Unsafe.arrayGet(values, from));
erase(from);
}
private void rehash() {
int size = size();
int newCapacity = capacity * 2;
mask = newCapacity - 1;
free = capacity = newCapacity;
int arrayCapacity = (int) (newCapacity / loadFactor);
long[] oldValues = values;
int[] oldKeys = keys;
this.keys = new int[arrayCapacity];
this.values = new long[arrayCapacity];
Arrays.fill(keys, noEntryKeyValue);
free -= size;
for (int i = oldKeys.length; i-- > 0; ) {
int key = Unsafe.arrayGet(oldKeys, i);
if (key != noEntryKeyValue) {
final int index = keyIndex(key);
Unsafe.arrayPut(keys, index, key);
Unsafe.arrayPut(values, index, Unsafe.arrayGet(oldValues, i));
}
}
}
}
/*******************************************************************************
* ___ _ ____ ____
* / _ \ _ _ ___ ___| |_| _ \| __ )
* | | | | | | |/ _ \/ __| __| | | | _ \
* | |_| | |_| | __/\__ \ |_| |_| | |_) |
* \__\_\\__,_|\___||___/\__|____/|____/
*
* Copyright (C) 2014-2019 Appsicle
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
package com.questdb.std;
import java.util.Arrays;
public class LongLongHashMap extends AbstractLongHashSet {
private static final int noEntryValue = -1;
private long[] values;
public LongLongHashMap() {
this(8);
}
public LongLongHashMap(int initialCapacity) {
this(initialCapacity, 0.5f);
}
private LongLongHashMap(int initialCapacity, double loadFactor) {
super(initialCapacity, loadFactor);
values = new long[keys.length];
clear();
}
public long get(long key) {
return valueAt(keyIndex(key));
}
public void put(long key, long value) {
putAt(keyIndex(key), key, value);
}
public void putAt(int index, long key, long value) {
if (index < 0) {
Unsafe.arrayPut(values, -index - 1, value);
} else {
Unsafe.arrayPut(keys, index, key);
Unsafe.arrayPut(values, index, value);
if (--free == 0) {
rehash();
}
}
}
public long valueAt(int index) {
return index < 0 ? Unsafe.arrayGet(values, -index - 1) : noEntryValue;
}
@Override
protected void erase(int index) {
Unsafe.arrayPut(keys, index, this.noEntryKeyValue);
}
@Override
protected void move(int from, int to) {
Unsafe.arrayPut(keys, to, Unsafe.arrayGet(keys, from));
Unsafe.arrayPut(values, to, Unsafe.arrayGet(values, from));
erase(from);
}
private void rehash() {
int size = size();
int newCapacity = capacity * 2;
mask = newCapacity - 1;
free = capacity = newCapacity;
int arrayCapacity = (int) (newCapacity / loadFactor);
long[] oldValues = values;
long[] oldKeys = keys;
this.keys = new long[arrayCapacity];
this.values = new long[arrayCapacity];
Arrays.fill(keys, noEntryKeyValue);
free -= size;
for (int i = oldKeys.length; i-- > 0; ) {
long key = Unsafe.arrayGet(oldKeys, i);
if (key != noEntryKeyValue) {
final int index = keyIndex(key);
Unsafe.arrayPut(keys, index, key);
Unsafe.arrayPut(values, index, Unsafe.arrayGet(oldValues, i));
}
}
}
}
\ No newline at end of file
/*******************************************************************************
* ___ _ ____ ____
* / _ \ _ _ ___ ___| |_| _ \| __ )
* | | | | | | |/ _ \/ __| __| | | | _ \
* | |_| | |_| | __/\__ \ |_| |_| | |_) |
* \__\_\\__,_|\___||___/\__|____/|____/
*
* Copyright (C) 2014-2019 Appsicle
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
package com.questdb.std;
import org.junit.Assert;
import org.junit.Test;
public class IntLongHashMapTest {
@Test
public void testAll() {
Rnd rnd = new Rnd();
// populate map
IntLongHashMap map = new IntLongHashMap();
final int N = 1000;
for (int i = 0; i < N; i++) {
long value = i + 1;
map.put(i, value);
}
Assert.assertEquals(N, map.size());
rnd.reset();
// assert that map contains the values we just added
for (int i = 0; i < N; i++) {
Assert.assertFalse(map.excludes(i));
Assert.assertEquals(i + 1, map.get(i));
}
Rnd rnd2 = new Rnd();
rnd.reset();
// remove some keys and assert that the size() complies
int removed = 0;
for (int i = 0; i < N; i++) {
if (rnd2.nextPositiveInt() % 16 == 0) {
Assert.assertTrue(map.remove(i) > -1);
removed++;
Assert.assertEquals(N - removed, map.size());
}
}
// if we didn't remove anything test has no value
Assert.assertTrue(removed > 0);
rnd2.reset();
rnd.reset();
Rnd rnd3 = new Rnd();
// assert that keys we didn't remove are still there and
// keys we removed are not
for (int i = 0; i < N; i++) {
int value = rnd.nextInt();
if (rnd2.nextPositiveInt() % 16 == 0) {
Assert.assertTrue(map.excludes(i));
} else {
Assert.assertFalse(map.excludes(i));
int index = map.keyIndex(i);
Assert.assertEquals(i + 1, map.valueAt(index));
// update value
map.putAt(index, value, rnd3.nextLong());
}
}
// assert that update is visible correctly
rnd3.reset();
rnd2.reset();
rnd.reset();
// assert that keys we didn't remove are still there and
// keys we removed are not
for (int i = 0; i < N; i++) {
if (rnd2.nextPositiveInt() % 16 == 0) {
Assert.assertTrue(map.excludes(i));
} else {
Assert.assertFalse(map.excludes(i));
Assert.assertEquals(rnd3.nextLong(), map.get(i));
}
}
}
}
/*******************************************************************************
* ___ _ ____ ____
* / _ \ _ _ ___ ___| |_| _ \| __ )
* | | | | | | |/ _ \/ __| __| | | | _ \
* | |_| | |_| | __/\__ \ |_| |_| | |_) |
* \__\_\\__,_|\___||___/\__|____/|____/
*
* Copyright (C) 2014-2019 Appsicle
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
package com.questdb.std;
import org.junit.Assert;
import org.junit.Test;
public class LongLongHashMapTest {
@Test
public void testAll() {
Rnd rnd = new Rnd();
// populate map
LongLongHashMap map = new LongLongHashMap();
final int N = 1000;
for (int i = 0; i < N; i++) {
long value = i + 1;
map.put(i, value);
}
Assert.assertEquals(N, map.size());
rnd.reset();
// assert that map contains the values we just added
for (int i = 0; i < N; i++) {
Assert.assertFalse(map.excludes(i));
Assert.assertEquals(i + 1, map.get(i));
}
Rnd rnd2 = new Rnd();
rnd.reset();
// remove some keys and assert that the size() complies
int removed = 0;
for (int i = 0; i < N; i++) {
if (rnd2.nextPositiveInt() % 16 == 0) {
Assert.assertTrue(map.remove(i) > -1);
removed++;
Assert.assertEquals(N - removed, map.size());
}
}
// if we didn't remove anything test has no value
Assert.assertTrue(removed > 0);
rnd2.reset();
rnd.reset();
Rnd rnd3 = new Rnd();
// assert that keys we didn't remove are still there and
// keys we removed are not
for (int i = 0; i < N; i++) {
int value = rnd.nextInt();
if (rnd2.nextPositiveInt() % 16 == 0) {
Assert.assertTrue(map.excludes(i));
} else {
Assert.assertFalse(map.excludes(i));
int index = map.keyIndex(i);
Assert.assertEquals(i + 1, map.valueAt(index));
// update value
map.putAt(index, value, rnd3.nextLong());
}
}
// assert that update is visible correctly
rnd3.reset();
rnd2.reset();
rnd.reset();
// assert that keys we didn't remove are still there and
// keys we removed are not
for (int i = 0; i < N; i++) {
if (rnd2.nextPositiveInt() % 16 == 0) {
Assert.assertTrue(map.excludes(i));
} else {
Assert.assertFalse(map.excludes(i));
Assert.assertEquals(rnd3.nextLong(), map.get(i));
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册