All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.databene.commons.OrderedMap Maven / Gradle / Ivy

Go to download

'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.

There is a newer version: 1.0.11
Show 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 t) {
        for (Map.Entry 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();
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy