216 lines
5.5 KiB
Java
216 lines
5.5 KiB
Java
/*******************************************************************************
|
|
* Copyright (c) 2002 - 2006 IBM Corporation.
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*
|
|
* Contributors:
|
|
* IBM Corporation - initial API and implementation
|
|
*******************************************************************************/
|
|
package com.ibm.wala.util.collections;
|
|
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Iterator;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import com.ibm.wala.util.debug.Assertions;
|
|
|
|
/**
|
|
*
|
|
* This implementation of Map chooses between one of two implementations,
|
|
* depending on the size of the map.
|
|
*
|
|
* @author sfink
|
|
*/
|
|
public class BimodalMap<K, V> implements Map<K, V> {
|
|
|
|
// what's the cutoff between small and big maps?
|
|
// this may be a time-space tradeoff; the caller must determine if
|
|
// it's willing to put up with slower random access in exchange for
|
|
// smaller footprint.
|
|
private final int cutOff;
|
|
|
|
/**
|
|
* The implementation we delegate to
|
|
*/
|
|
private Map<K, V> backingStore;
|
|
|
|
/**
|
|
* @param cutoff
|
|
* the map size at which to switch from the small map implementation
|
|
* to the large map implementation
|
|
*/
|
|
public BimodalMap(int cutoff) {
|
|
this.cutOff = cutoff;
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.util.Map#size()
|
|
*/
|
|
public int size() {
|
|
return (backingStore == null) ? 0 : backingStore.size();
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.util.Map#isEmpty()
|
|
*/
|
|
public boolean isEmpty() {
|
|
return (backingStore == null) ? true : backingStore.isEmpty();
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.util.Map#containsKey(java.lang.Object)
|
|
*/
|
|
public boolean containsKey(Object key) {
|
|
return (backingStore == null) ? false : backingStore.containsKey(key);
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.util.Map#containsValue(java.lang.Object)
|
|
*/
|
|
public boolean containsValue(Object value) {
|
|
return (backingStore == null) ? false : backingStore.containsValue(value);
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.util.Map#get(java.lang.Object)
|
|
*/
|
|
public V get(Object key) {
|
|
return (backingStore == null) ? null : backingStore.get(key);
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.util.Map#put(java.lang.Object, java.lang.Object)
|
|
*/
|
|
public V put(K key, V value) {
|
|
if (backingStore == null) {
|
|
backingStore = new SmallMap<K, V>();
|
|
backingStore.put(key, value);
|
|
return null;
|
|
} else {
|
|
if (backingStore instanceof SmallMap) {
|
|
V result = backingStore.put(key, value);
|
|
if (backingStore.size() > cutOff) {
|
|
transferBackingStore();
|
|
}
|
|
return result;
|
|
} else {
|
|
return backingStore.put(key, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Switch backing implementation from a SmallMap to a HashMap
|
|
*/
|
|
private void transferBackingStore() {
|
|
if (Assertions.verifyAssertions) {
|
|
Assertions._assert(backingStore instanceof SmallMap);
|
|
}
|
|
SmallMap<K, V> S = (SmallMap<K,V>) backingStore;
|
|
backingStore = HashMapFactory.make(2 * S.size());
|
|
for (Iterator<K> it = S.keySet().iterator(); it.hasNext();) {
|
|
K key = it.next();
|
|
V value = S.get(key);
|
|
backingStore.put(key, value);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.util.Map#remove(java.lang.Object)
|
|
*/
|
|
public V remove(Object key) {
|
|
return (backingStore == null) ? null : backingStore.remove(key);
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.util.Map#putAll(java.util.Map)
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public void putAll(Map<? extends K, ? extends V> t) {
|
|
if (backingStore == null) {
|
|
int size = t.size();
|
|
if (size > cutOff) {
|
|
backingStore = HashMapFactory.make();
|
|
} else {
|
|
backingStore = new SmallMap<K, V>();
|
|
}
|
|
backingStore.putAll(t);
|
|
return;
|
|
} else {
|
|
if (backingStore instanceof SmallMap) {
|
|
if (t.size() > cutOff) {
|
|
Map<K, V> old = backingStore;
|
|
backingStore = (Map<K, V>) HashMapFactory.make(t);
|
|
backingStore.putAll(old);
|
|
} else {
|
|
backingStore.putAll(t);
|
|
if (backingStore.size() > cutOff) {
|
|
transferBackingStore();
|
|
}
|
|
return;
|
|
}
|
|
} else {
|
|
backingStore.putAll(t);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.util.Map#clear()
|
|
*/
|
|
public void clear() {
|
|
backingStore = null;
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.util.Map#keySet()
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public Set<K> keySet() {
|
|
return (Set<K>) ((backingStore == null) ? Collections.emptySet() : backingStore.keySet());
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.util.Map#values()
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public Collection<V> values() {
|
|
return (Collection<V>) ((backingStore == null) ? Collections.emptySet() : backingStore.values());
|
|
}
|
|
|
|
/*
|
|
* (non-Javadoc)
|
|
*
|
|
* @see java.util.Map#entrySet()
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public Set<Map.Entry<K, V>> entrySet() {
|
|
return (Set<Entry<K, V>>) ((backingStore == null) ? Collections.emptySet() : backingStore.entrySet());
|
|
}
|
|
} |