com.ibm.commons.util.DoubleMap Maven / Gradle / Ivy
The newest version!
/*
* © Copyright IBM Corp. 2010
*
* 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.ibm.commons.util;
/**
* Map that can efficiently be accessed by either the key or the value.
*
*
*/
public class DoubleMap {
private int slotCount;
private int size;
// Hash map entries
private MapEntry[] keyEntries;
private MapEntry[] valueEntries;
private static final class MapEntry {
// List in the Hash table
MapEntry keyPrevHash;
MapEntry keyNextHash;
MapEntry valuePrevHash;
MapEntry valueNextHash;
int keyHashCode;
int valueHashCode;
Object key;
Object value;
MapEntry(Object key, Object value) {
this.key = key;
this.value = value;
this.keyHashCode = key.hashCode();
this.valueHashCode = value.hashCode();
}
}
public DoubleMap() {
this(13); // See Aho for good values here...
}
public DoubleMap(int slotCount) {
this.slotCount = slotCount;
this.keyEntries = new MapEntry[slotCount];
this.valueEntries = new MapEntry[slotCount];
}
public int size() {
return size;
}
public void clear() {
this.size = 0;
this.keyEntries = new MapEntry[slotCount];
this.valueEntries = new MapEntry[slotCount];
}
public void put(K key, V value) {
MapEntry e = new MapEntry(key, value);
put(e);
}
public void removeEntryByKey(K key) {
MapEntry e = getEntryByKey(key);
if (e != null) {
removeEntry(e);
}
}
public void removeEntryByValue(V value) {
MapEntry e = getEntryByValue(value);
if (e != null) {
removeEntry(e);
}
}
public V getNameByKey(K key) {
MapEntry e = getEntryByKey(key);
if (e != null) {
return (V)e.value;
}
return null;
}
public K getIdByValue(V value) {
MapEntry e = getEntryByValue(value);
if (e != null) {
return (K)e.key;
}
return null;
}
private final int getSlot(int hashCode) {
return (hashCode & 0x7FFFFFFF) % slotCount;
}
private final MapEntry getEntryByKey(K key) {
int hashCode = key.hashCode();
for (MapEntry e = keyEntries[getSlot(hashCode)]; e != null; e = e.keyNextHash) {
if (e.keyHashCode == hashCode && e.key.equals(key)) {
return e;
}
}
return null;
}
private final MapEntry getEntryByValue(V value) {
int hashCode = value.hashCode();
for (MapEntry e = valueEntries[getSlot(hashCode)]; e != null; e = e.valueNextHash) {
if (e.valueHashCode == hashCode && e.value.equals(value)) {
return e;
}
}
return null;
}
private void put(MapEntry e) {
// Insert the new entry in the ID HashTable
int keySlot = getSlot(e.keyHashCode);
e.keyNextHash = keyEntries[keySlot];
if (e.keyNextHash != null) {
e.keyNextHash.keyPrevHash = e;
}
keyEntries[keySlot] = e;
// Insert the new entry in the Name HashTable
int valueSlot = getSlot(e.valueHashCode);
e.valueNextHash = valueEntries[valueSlot];
if (e.valueNextHash != null) {
e.valueNextHash.valuePrevHash = e;
}
valueEntries[valueSlot] = e;
size++;
}
private final void removeEntry(MapEntry e) {
// Remove the entry from the ID hashtable
if (e.keyPrevHash != null) {
e.keyPrevHash.keyNextHash = e.keyNextHash;
} else {
keyEntries[getSlot(e.keyHashCode)] = e.keyNextHash;
}
if (e.keyNextHash != null) {
e.keyNextHash.keyPrevHash = e.keyPrevHash;
}
// Remove the entry from the Name hashtable
if (e.valuePrevHash != null) {
e.valuePrevHash.valueNextHash = e.valueNextHash;
} else {
valueEntries[getSlot(e.valueHashCode)] = e.valueNextHash;
}
if (e.valueNextHash != null) {
e.valueNextHash.valuePrevHash = e.valuePrevHash;
}
// Decrease the map count
size--;
}
}