SmallMap.java

package eu.javaexperience.collection.map;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import eu.javaexperience.collection.iterator.NotNullIterable;
import eu.javaexperience.collection.set.ArrayAsSetRO;
import eu.javaexperience.interfaces.simple.publish.SimplePublish3;
import eu.javaexperience.reflect.Mirror;

/**
 * TODO Refactor: use only one array instead of K and V
 * */
public class SmallMap<K,V> implements Map<K,V>, Cloneable, Serializable
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	Object[] keys;
	Object[] vals;
	int ep  = 0;
	int kvs = 0;
	
	public SmallMap()
	{
		keys = Mirror.emptyObjectArray;
		vals = Mirror.emptyObjectArray;
	}
	
	public SmallMap(Map<K, V> from)
	{
		int initalLength = from.size();
		keys = new Object[initalLength];
		vals = new Object[initalLength];
		
		for(java.util.Map.Entry<K, V> kv:from.entrySet())
		{
			put(kv.getKey(), kv.getValue());
		}
	}

	
	public SmallMap(int initalLength)
	{
		keys = new Object[initalLength];
		vals = new Object[initalLength];
	}
	
	@Override
	public int size()
	{
		return kvs;
	}

	@Override
	public boolean isEmpty()
	{
		return kvs == 0;
	}

	@Override
	public boolean containsKey(Object paramObject)
	{
		for(int i=0;i<ep;i++)
			if(paramObject.equals(keys[i]))
				return true;
		
		return false;
	}

	@Override
	public boolean containsValue(Object paramObject)
	{
		for(int i=0;i<ep;i++)
			if(paramObject.equals(vals[i]))
				return true;
		
		return false;
	}

	@Override
	public V get(Object paramObject)
	{
		if(paramObject == null)
			return null;
		
		for(int i=0;i<ep;i++)
			if(paramObject.equals(keys[i]))
				return (V) vals[i];
		
		return null;
	}

	private void inc()
	{
		if(ep == keys.length)
		{
			int len = keys.length*2;
			if(0 == len)
			{
				len = 4;
			}
			
			keys = Arrays.copyOf(keys, len);
			vals = Arrays.copyOf(vals, len);
		}
	}
	
	@Override
	public V put(K paramK, V paramV)
	{
		//ha már benne van érték felülírás
		for(int i=0;i<ep;i++)
			if(paramK.equals(keys[i]))
			{
				Object ret = vals[i];
				vals[i] = paramV;
				return (V) ret;
			}

		//ha a kulcsok végpontja és a tömb végpontja ugyanaz, akkor nincs benne null, a végére hozzáadjuk
		if(ep == kvs)
		{
			inc();
			keys[kvs++] = paramK;
			vals[ep++] = paramV;
		}//köztes beszúrás
		else
			for(int i=0;i<ep;i++)
				if(keys[i] == null)
				{
					keys[i] = paramK;
					vals[i] = paramV;
					kvs++;
					inc();
					break;
				}

		return null;
	}

	@Override
	public V remove(Object paramObject)
	{
		for(int i=0;i<ep;i++)
			if(paramObject.equals(keys[i]))
			{
				Object ret = vals[i];
				keys[i] = null;
				vals[i] = null;
				
				//csönkkent a kulcs-érték párok mérete
				kvs--;
				
				//ha a legvégéről lett kitörölve akkor a vége mutatót visszább húzzuk
				if(i == ep-1)
					ep--;

				return (V) ret;
			}	
	
		return null;
	}

	@Override
	public void putAll(Map<? extends K, ? extends V> paramMap)
	{
		for(java.util.Map.Entry<? extends K, ? extends V> kv:paramMap.entrySet())
			put(kv.getKey(), kv.getValue());
	}

	@Override
	public void clear()
	{
		for(int i=0;i<ep;i++)
			keys[i] = vals[i] = null;
		
		ep = 0;
		kvs = 0;
	}

	@Override
	public Set<K> keySet()
	{
		Object[] ret = new Object[kvs];
		int cep = 0;
		for(int i = 0;i < ep;i++)
			if(keys[i] != null)
				ret[cep++] = keys[i];
		
		if(cep == ret.length)
		{
			return new ArrayAsSetRO(ret);
		}
		else
		{
			return new ArrayAsSetRO(Arrays.copyOf(ret, cep));
		}
	}

	@Override
	public Collection<V> values()
	{
		Object[] ret = new Object[kvs];
		int aep = 0;
		for(int i=0;i<ep;i++)
		{
			if(vals[i] != null)
				ret[aep++] = vals[i];
		}
		
		if(aep == ret.length)
		{
			return new ArrayAsSetRO(ret);
		}
		else
		{
			return new ArrayAsSetRO(Arrays.copyOf(ret, aep));
		}
	}

	public K getKeyByValue(V val)
	{
		for(int i=0;i<ep;i++)
			if(val.equals(vals[i]))
				return (K) keys[i];
		
		return null;
	}
	
	@Override
	public Set<java.util.Map.Entry<K, V>> entrySet()
	{
		KeyVal<K,V>[] ret = new KeyVal[kvs];
		int cep = 0;
		for(int i=0;i<ep;i++)
		{
			if(keys[i] != null)
			{
				ret[cep++] = new KeyVal<K, V>((K)keys[i],(V) vals[i]);
			}
		}
		return new ArrayAsSetRO(ret);
	}
	
	public SmallMap<K,V> clone()
	{
		SmallMap<K,V> ret = new SmallMap();
		ret.keys = Arrays.copyOf(keys, keys.length);
		ret.vals = Arrays.copyOf(vals, vals.length);
		ret.kvs = kvs;
		ret.ep = ep;
		
		return ret;
	}
	
	public Iterable<K> getKeyIterator()
	{
		return (Iterable<K>) NotNullIterable.whitoutNulls(keys);
	}
	
	/**
	 * go trough all key and value and publish with the specified
	 * SimplePublis, you can specify an extra parameter which will be also
	 * published.
	 * 	
	 *  Purpose:
	 *  you need only one SimplePublish instance to process all key and value.
	 *  this technique doesn't need extra instance creation
	 *  (set and entries)
	 * */
	public <T> void each(SimplePublish3<K, V, T> pub, T param)
	{
		for(int i=0;i<ep;++i)
		{
			pub.publish((K) keys[i], (V) vals[i], param);
		}
	}
	
	
	public String toString()
	{
		return MapTools.toStringMultiline(this);
	}
}