blob: 9bbc74b73ca1c2451c59c5ba052faa71d65960d0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2010 IBM Corporation and others.
* 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 org.eclipse.osgi.internal.module;
import java.lang.reflect.Array;
import java.util.*;
/*
* A MappedList maps values into keyed list arrays. All values with the same key are stored
* into the same array. Extending classes may override the sort method to sort the individual
* arrays in the MappedList. By default the MappedList appends new values to the end of the array.
*/
public class MappedList<K, V> {
// the mapping with key -> Object[] mapping
protected final HashMap<K, Object> internal = new HashMap();
protected final Class<V> valueClass;
protected final V[] empty;
public MappedList(Class<V> valueClass) {
this.valueClass = valueClass;
empty = (V[]) Array.newInstance(valueClass, 0);
}
public void put(K key, V value) {
Object existing = internal.get(key);
if (existing == null) {
internal.put(key, value);
} else {
V[] existingValues;
if (existing.getClass().isArray()) {
existingValues = (V[]) existing;
} else {
existingValues = (V[]) Array.newInstance(valueClass, 1);
existingValues[0] = (V) existing;
}
// insert the new value
int index = insertionIndex(existingValues, value);
V[] newValues = (V[]) Array.newInstance(valueClass, existingValues.length + 1);
System.arraycopy(existingValues, 0, newValues, 0, index);
newValues[index] = value;
System.arraycopy(existingValues, index, newValues, index + 1, existingValues.length - index);
internal.put(key, newValues); // overwrite the old values in the map
}
}
protected int insertionIndex(V[] existing, V value) {
// a MappedList is by default not sorted so just insert at the end
// extending classes may override this method to provide an index that retains sorted order
return existing.length;
}
// removes all values with the specified key
public V[] remove(K key) {
return get(key, true);
}
// gets all values with the specified key
public V[] get(K key) {
return get(key, false);
}
// gets all values with the specified and optionally removes them
private V[] get(K key, boolean remove) {
Object result = remove ? internal.remove(key) : internal.get(key);
if (result != null && result.getClass().isArray())
return (V[]) result;
if (result == null)
return empty;
V[] singleValue = (V[]) Array.newInstance(valueClass, 1);
singleValue[0] = (V) result;
return singleValue;
}
// returns the number of keyed lists
public int getSize() {
return internal.size();
}
// returns all values of all keys
public V[] getAllValues() {
if (getSize() == 0)
return empty;
ArrayList<V> results = new ArrayList(getSize());
Iterator iter = internal.values().iterator();
while (iter.hasNext()) {
Object value = iter.next();
if (value.getClass().isArray()) {
Object[] values = (Object[]) value;
for (int i = 0; i < values.length; i++)
results.add((V) values[i]);
} else
results.add((V) value);
}
return results.toArray(empty);
}
// removes all keys from the map
public void clear() {
internal.clear();
}
}