org.databene.commons.OrderedMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of databene-commons Show documentation
Show all versions of databene-commons Show documentation
'databene commons' is an open source Java library by Volker Bergmann.
It provides extensions to the Java core library by utility classes, abstract concepts
and concrete implementations.
The newest version!
/*
* Copyright (C) 2004-2015 Volker Bergmann ([email protected]).
* All rights reserved.
*
* 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.databene.commons;
import java.io.Serializable;
import java.util.*;
import org.databene.commons.collection.ListBasedSet;
import org.databene.commons.collection.MapEntry;
import org.databene.commons.collection.MapProxy;
/**
* Map implementation that tracks the order in which elements where added
* and returns them in that order by the values() method.
* This is useful for all cases in which elements will be queried by a key
* and processed but need to be stored in the original order.
* Created: 06.01.2007 09:04:17
* @param the key type
* @param the value type
* @author Volker Bergmann
*/
public class OrderedMap implements Map, Serializable {
private static final long serialVersionUID = -6081918861041975388L;
private Map keyIndices;
protected List values;
// constructors ----------------------------------------------------------------------------------------------------
public OrderedMap() {
keyIndices = new HashMap();
values = new ArrayList();
}
public OrderedMap(int initialCapacity) {
keyIndices = new HashMap(initialCapacity);
values = new ArrayList(initialCapacity);
}
public OrderedMap(int initialCapacity, float loadFactor) {
keyIndices = new HashMap(initialCapacity, loadFactor);
values = new ArrayList(initialCapacity);
}
public OrderedMap(Map source) {
this(source.size());
for (Entry entry : source.entrySet())
put(entry.getKey(), entry.getValue());
}
// custom interface ------------------------------------------------------------------------------------------------
public Map.Entry getEntry(K key) {
if (containsKey(key))
return new MapEntry(key, get(key));
else
return null;
}
// Map interface implementation ------------------------------------------------------------------------------------
@Override
public int size() {
return values.size();
}
@Override
public boolean isEmpty() {
return values.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return keyIndices.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return values.contains(value);
}
@Override
public V get(Object key) {
Integer index = keyIndices.get(key);
if (index == null)
return null;
return values.get(index);
}
@Override
public V put(K key, V value) {
Integer index = keyIndices.get(key);
if (index != null)
return values.set(index, value);
else {
keyIndices.put(key, values.size());
values.add(value);
return null;
}
}
@Override
public V remove(Object key) {
Integer index = keyIndices.remove(key);
if (index != null) {
V oldValue = values.get(index);
values.remove((int)index);
for (Entry entry : keyIndices.entrySet()) {
int entryIndex = entry.getValue();
if (entryIndex > index)
entry.setValue(entryIndex - 1);
}
return oldValue;
} else
return null;
}
@Override
public void putAll(Map extends K, ? extends V> t) {
for (Map.Entry extends K, ? extends V> entry : t.entrySet())
put(entry.getKey(), entry.getValue());
}
@Override
public void clear() {
keyIndices.clear();
values.clear();
}
@Override
public Set keySet() {
List tmp = new ArrayList(values.size());
// set the used array size by adding nulls
for (int i = 0; i < values.size(); i++)
tmp.add(null);
// set the array elements themselves
for (Entry entry : keyIndices.entrySet())
tmp.set(entry.getValue(), entry.getKey());
return new ListBasedSet(tmp);
}
@Override
public List values() {
return new ArrayList(values);
}
@Override
@SuppressWarnings("unchecked")
public Set> entrySet() {
Map.Entry[] tmp = new Map.Entry[values.size()];
for (Map.Entry entry : keyIndices.entrySet()) {
Integer index = entry.getValue();
tmp[index] = new ProxyEntry(entry.getKey(), index);
}
return new ListBasedSet>(tmp);
}
// List/Vector interface -------------------------------------------------------------------------------------------
public V valueAt(int index) {
return values.get(index);
}
public int indexOfValue(V value) {
return values.indexOf(value);
}
/**
* Returns an array containing all of the values in this map in proper sequence.
* Obeys the general contract of the Collection.toArray method.
* @return an array containing all of the elements in this list in proper sequence.
*/
public Object[] toArray() {
return values.toArray();
}
/**
* Returns an array containing all of the values in this map in proper sequence;
* the runtime type of the returned array is that of the specified array.
* Obeys the general contract of the Collection.toArray(Object[]) method.
* @param a the array into which the elements of this list are to be stored, if it is big enough; otherwise, a new array of the same runtime type is allocated for this purpose.
* @param the component type of the result array
* @return an array containing the values of this map.
* @throws ArrayStoreException if the runtime type of the specified array is not a supertype of the runtime type of every element in this list.
* @throws NullPointerException - if the specified array is null.
*/
public T[] toArray(T[] a) {
return values.toArray(a);
}
// specific interface ----------------------------------------------------------------------------------------------
public List internalValues() {
return values;
}
public boolean equalsIgnoreOrder(Map that) {
if (this == that)
return true;
if (this.size() != that.size())
return false;
for (Map.Entry entry : that.entrySet()) {
K key = entry.getKey();
if (!this.containsKey(key))
return false;
if (!NullSafeComparator.equals(this.get(key), that.get(key)))
return false;
}
return true;
}
private class ProxyEntry implements Map.Entry {
private K key;
private int index;
public ProxyEntry(K key, int index) {
this.key = key;
this.index = index;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return OrderedMap.this.values.get(index);
}
@Override
public V setValue(V value) {
return OrderedMap.this.values.set(index, value);
}
@Override
public String toString() {
return String.valueOf(key) + '=' + getValue();
}
}
// java.lang.Object overrides --------------------------------------------------------------------------------------
@SuppressWarnings("rawtypes")
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || !(o instanceof Map))
return false;
while (o instanceof MapProxy)
o = ((MapProxy) o).getRealMap();
final OrderedMap that = (OrderedMap) o;
return (this.values.equals(that.values) && this.keyIndices.equals(that.keyIndices));
}
@Override
public int hashCode() {
return keyIndices.hashCode() * 29 + values.hashCode();
}
@Override
public String toString() {
ListBasedSet> entries = (ListBasedSet>)entrySet();
StringBuilder buffer = new StringBuilder("{");
if (entries.size() > 0)
buffer.append(entries.get(0));
for (int i = 1; i < entries.size(); i++)
buffer.append(", ").append(entries.get(i));
buffer.append('}');
return buffer.toString();
}
}