org.nustaq.serialization.util.FSTIdentity2IdMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fst Show documentation
Show all versions of fst Show documentation
A fast java serialization drop in-replacement and some serialization based utils such as Structs and OffHeap Memory.
/*
* Copyright 2014 Ruediger Moeller.
*
* 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 org.nustaq.serialization.util;
import java.util.ArrayList;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* User: ruedi
* Date: 20.11.12
* Time: 19:57
* To change this template use File | Settings | File Templates.
*/
public class FSTIdentity2IdMap {
private static final int RESERVE = 4;
private static final int MAX_DEPTH = 4;
static int[] prim = {
3, 5, 7, 11, 13, 17, 19, 23, 29, 37, 67, 97, 139,
211, 331, 641, 1097, 1531, 2207, 3121, 5059, 7607, 10891,
15901, 19993, 30223, 50077, 74231, 99991, 150001, 300017,
1000033, 1500041, 200033, 3000077, 5000077, 10000019
};
static int adjustSize(int size) {
for (int i = 0; i < prim.length - 1; i++) {
if (size < prim[i]) {
return prim[i] + RESERVE;
}
}
return size + RESERVE;
}
private static final int GROFAC = 2;
private int mask;
public Object[] mKeys;
private int klen;
private int mValues[];
private int mNumberOfElements;
private FSTIdentity2IdMap next;
private List linearScanList; // in case of too deep nesting, this one is filled and linear search is applied
private List linearScanVals; // in case of too deep nesting, this one is filled and linear search is applied
public FSTIdentity2IdMap(int initialSize) {
if (initialSize < 2) {
initialSize = 2;
}
initialSize = adjustSize(initialSize * GROFAC);
mKeys = new Object[initialSize];
mValues = new int[initialSize];
mNumberOfElements = 0;
mask = (Integer.highestOneBit(initialSize) << 1) - 1;
klen = initialSize - 4;
}
public int size() {
if ( linearScanList != null )
return linearScanList.size();
return mNumberOfElements + (next != null ? next.size() : 0);
}
final public int putOrGet(Object key, int value) {
int hash = calcHash(key);
return putOrGetHash(key, value, hash, this, 0);
}
final int putOrGetHash(Object key, int value, int hash, FSTIdentity2IdMap parent, int depth ) {
if ( linearScanList != null ) {
for (int i = 0; i < linearScanList.size(); i++) {
Object o = linearScanList.get(i);
if ( o == key ) {
return linearScanVals.get(i);
}
}
linearScanList.add(key);
linearScanVals.add(value);
return Integer.MIN_VALUE;
}
if (mNumberOfElements * GROFAC > mKeys.length) {
if (parent != null) {
if ((parent.mNumberOfElements + mNumberOfElements) * GROFAC > parent.mKeys.length) {
parent.resize(parent.mKeys.length * GROFAC);
return parent.putOrGet(key, value);
} else {
resize(mKeys.length * GROFAC);
}
} else {
resize(mKeys.length * GROFAC);
}
}
Object[] mKeys = this.mKeys;
// int idx = calcIndexFromHash(hash, mKeys);
int idx = calcIndexFromHash(hash, mKeys);
Object mKeyAtIdx = mKeys[idx];
if (mKeyAtIdx == null) // new
{
mNumberOfElements++;
mValues[idx] = value;
mKeys[idx] = key;
return Integer.MIN_VALUE;
} else if (mKeyAtIdx == key) // present
{
return mValues[idx];
} else {
Object mKeyAtIdxPlus1 = mKeys[idx + 1];
if (mKeyAtIdxPlus1 == null) // new
{
mNumberOfElements++;
mValues[idx + 1] = value;
mKeys[idx + 1] = key;
return Integer.MIN_VALUE;
} else if (mKeyAtIdxPlus1 == key) // present
{
return mValues[idx + 1];
} else {
Object mKeysAtIndexPlus2 = mKeys[idx + 2];
if (mKeysAtIndexPlus2 == null) // new
{
mNumberOfElements++;
mValues[idx + 2] = value;
mKeys[idx + 2] = key;
return Integer.MIN_VALUE;
} else if (mKeysAtIndexPlus2 == key) // present
{
return mValues[idx + 2];
} else {
return putOrGetNext(hash, key, value, depth+1);
}
}
}
}
final int putOrGetNext(final int hash, final Object key, final int value, int depth) {
if (next == null) { // new
int newSiz = mKeys.length / 10;
next = new FSTIdentity2IdMap(newSiz);
if ( depth > MAX_DEPTH ) {
next.linearScanVals = new ArrayList<>(3);
next.linearScanList = new ArrayList<>(3);
}
next.putHash(key, value, hash, this, depth);
return Integer.MIN_VALUE;
}
return next.putOrGetHash(key, value, hash, this, depth+1);
}
final public void put(Object key, int value) {
int hash = calcHash(key);
putHash(key, value, hash, this, 0);
}
final void putHash(Object key, int value, int hash, FSTIdentity2IdMap parent, int depth) {
if ( linearScanList != null ) {
for (int i = 0; i < linearScanList.size(); i++) {
Object o = linearScanList.get(i);
if ( o == key ) {
linearScanVals.set(i, value);
return;
}
}
linearScanList.add(key);
linearScanVals.add(value);
return;
}
if (mNumberOfElements * GROFAC > mKeys.length) {
if (parent != null) {
if ((parent.mNumberOfElements + mNumberOfElements) * GROFAC > parent.mKeys.length) {
parent.resize(parent.mKeys.length * GROFAC);
parent.put(key, value);
return;
} else {
resize(mKeys.length * GROFAC);
}
} else {
resize(mKeys.length * GROFAC);
}
}
Object[] mKeys = this.mKeys;
int idx = calcIndexFromHash(hash, mKeys);
if (mKeys[idx] == null) // new
{
mNumberOfElements++;
mValues[idx] = value;
mKeys[idx] = key;
} else if (mKeys[idx] == key) // overwrite
{
// bloom|=hash;
mValues[idx] = value;
} else {
if (mKeys[idx + 1] == null) // new
{
mNumberOfElements++;
mValues[idx + 1] = value;
mKeys[idx + 1] = key;
} else if (mKeys[idx + 1] == key) // overwrite
{
// bloom|=hash;
mValues[idx + 1] = value;
} else {
if (mKeys[idx + 2] == null) // new
{
mNumberOfElements++;
mValues[idx + 2] = value;
mKeys[idx + 2] = key;
} else if (mKeys[idx + 2] == key) // overwrite
{
// bloom|=hash;
mValues[idx + 2] = value;
} else {
putNext(hash, key, value, depth+1);
}
}
}
}
final void putNext(final int hash, final Object key, final int value, int depth) {
if (next == null) {
int newSiz = mKeys.length / 10;
next = new FSTIdentity2IdMap(newSiz);
if ( depth > MAX_DEPTH ) {
next.linearScanVals = new ArrayList<>(3);
next.linearScanList = new ArrayList<>(3);
}
}
next.putHash(key, value, hash, this, depth+1);
}
final public int get(final Object key) {
int hash = calcHash(key);
return getHash(key, hash);
}
final int getHash(final Object key, final int hash) {
if ( linearScanList != null ) {
for (int i = 0; i < linearScanList.size(); i++) {
Object o = linearScanList.get(i);
if ( o == key ) {
return linearScanVals.get(i);
}
}
return Integer.MIN_VALUE;
}
final int idx = calcIndexFromHash(hash, mKeys);
Object mapsKey = mKeys[idx];
if (mapsKey == null) // not found
{
return Integer.MIN_VALUE;
} else if (mapsKey == key) // found
{
return mValues[idx];
} else {
mapsKey = mKeys[idx + 1];
if (mapsKey == null) // not found
{
return Integer.MIN_VALUE;
} else if (mapsKey == key) // found
{
return mValues[idx + 1];
} else {
mapsKey = mKeys[idx + 2];
if (mapsKey == null) // not found
{
return Integer.MIN_VALUE;
} else if (mapsKey == key) // found
{
return mValues[idx + 2];
} else {
if (next == null) {
return Integer.MIN_VALUE;
}
return next.getHash(key, hash);
}
}
}
}
final void resize(int newSize) {
newSize = adjustSize(newSize);
Object[] oldTabKey = mKeys;
int[] oldTabVal = mValues;
mKeys = new Object[newSize];
mValues = new int[newSize];
mNumberOfElements = 0;
mask = (Integer.highestOneBit(newSize) << 1) - 1;
klen = newSize - RESERVE;
for (int n = 0; n < oldTabKey.length; n++) {
if (oldTabKey[n] != null) {
put(oldTabKey[n], oldTabVal[n]);
}
}
if (next != null) {
FSTIdentity2IdMap oldNext = next;
next = null;
oldNext.rePut(this);
}
}
private void rePut(FSTIdentity2IdMap kfstObject2IntMap) {
if ( linearScanList != null ) {
int size = linearScanList.size();
for (int i = 0; i < size; i++) {
Object key = linearScanList.get(i);
int value = linearScanVals.get(i);
kfstObject2IntMap.put(key, value);
}
return;
}
for (int i = 0; i < mKeys.length; i++) {
Object mKey = mKeys[i];
if (mKey != null) {
kfstObject2IntMap.put(mKey, mValues[i]);
}
}
if (next != null) {
next.rePut(kfstObject2IntMap);
}
}
final int calcIndexFromHash(int hash, Object[] mKeys) {
int res = hash & mask;
while (res >= klen) {
res = res >>> 1;
}
return res;
}
private static int calcHash(Object x) {
int h = System.identityHashCode(x);
// return h>>2;
return ((h << 1) - (h << 8)) & 0x7fffffff;
}
public void clear() {
if (size() == 0) {
return;
}
if ( linearScanList != null ) {
linearScanList.clear();
linearScanVals.clear();
}
FSTUtil.clear(mKeys);
FSTUtil.clear(mValues);
// Arrays.fill(mKeys,null);
// Arrays.fill(mValues,0);
mNumberOfElements = 0;
if (next != null) {
next.clear();
}
}
public void dump() {
for (int i = 0; i < mKeys.length; i++) {
Object mKey = mKeys[i];
if (mKey != null) {
System.out.println("" + mKey + " => " + mValues[i]);
}
}
if (next != null)
next.dump();
}
public int keysLength() {
return mKeys.length;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy