/**
* Copyright 2013-2016 Guoqiang Chen, Shanghai, China. All rights reserved.
*
* Author: Guoqiang Chen
* Email: subchen@gmail.com
* WebURL: https://github.com/subchen
*
* 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 jetbrick.collection;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.AbstractList;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
public class ListOrderedMap<K, V> extends AbstractMap<K, V> implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private final Map<K, LinkedEntry<K, V>> map;
private LinkedEntry<K, V> header;
public ListOrderedMap() {
map = new HashMap<K, LinkedEntry<K, V>>();
createHeader();
}
public ListOrderedMap(int initialCapacity) {
map = new HashMap<K, LinkedEntry<K, V>>(initialCapacity);
createHeader();
}
public ListOrderedMap(int initialCapacity, float loadFactor) {
map = new HashMap<K, LinkedEntry<K, V>>(initialCapacity, loadFactor);
createHeader();
}
public ListOrderedMap(Map<? extends K, ? extends V> m) {
this();
putAll(m);
}
private void createHeader() {
header = new LinkedEntry<K, V>();
header.prev = header.next = header;
}
// OrderedMap interface
public Entry<K, V> getEntry(int index) {
if (index < 0 || index >= size()) {
throw new IndexOutOfBoundsException();
}
LinkedEntry<K, V> entry = header.next;
for (int i = 0; i < index; i++) {
entry = entry.next;
}
return entry;
}
public K getKey(int index) {
return getEntry(index).getKey();
}
public V getValue(int index) {
return getEntry(index).getValue();
}
public Entry<K, V> put(int index, K key, V value) {
if (index < 0 || index > size()) throw new IndexOutOfBoundsException();
LinkedEntry<K, V> old = header.next;
boolean before = false;
for (int i = 0; i < index; i++) {
old = old.next;
if (key == old.key || (key != null && key.equals(old.key))) before = true;
}
if (before) old = old.next;
LinkedEntry<K, V> entry = map.get(key);
if (entry != null) {
if (index == size()) throw new IndexOutOfBoundsException();
if (entry != old) entry.moveBefore(old);
entry.value = value;
} else {
entry = new LinkedEntry<K, V>(key, value);
entry.insertBefore(old);
map.put(key, entry);
}
return old;
}
public void putAll(int index, Map<? extends K, ? extends V> map) {
for (Entry<? extends K, ? extends V> entry : map.entrySet())
put(index++, entry.getKey(), entry.getValue());
}
public Entry<K, V> remove(int index) {
Entry<K, V> entry = getEntry(index);
remove(entry.getKey());
return entry;
}
public Iterator<Map.Entry<K, V>> iterator() {
return new EntriesIterator();
}
public Entry<K, V>[] toArray() {
int size = size();
@SuppressWarnings("unchecked")
Entry<K, V>[] entries = new LinkedEntry[size];
LinkedEntry<K, V> entry = header.next;
for (int i = 0; i < size; i++) {
entries[i] = entry;
entry = entry.next;
}
return entries;
}
// Map interface
@Override
public V get(Object key) {
LinkedEntry<K, V> entry = map.get(key);
return entry != null ? entry.value : null;
}
@Override
public V put(K key, V value) {
LinkedEntry<K, V> entry = map.get(key);
if (entry != null) {
V old = entry.value;
entry.value = value;
return old;
} else {
entry = new LinkedEntry<K, V>(key, value);
entry.insertBefore(header);
map.put(key, entry);
return null;
}
}
@Override
public V remove(Object key) {
LinkedEntry<K, V> entry = map.get(key);
if (entry != null) {
entry.remove();
map.remove(key);
return entry.value;
} else
return null;
}
@Override
public boolean containsValue(Object value) {
if (value != null) {
for (V v : values())
if (value.equals(v)) return true;
} else {
for (V v : values())
if (v == null) return true;
}
return false;
}
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public void clear() {
map.clear();
createHeader();
}
private transient Set<Entry<K, V>> entries;
@Override
public Set<Entry<K, V>> entrySet() {
if (entries == null) entries = new AbstractSet<Entry<K, V>>() {
@Override
public int size() {
return map.size();
}
@Override
public Iterator<Entry<K, V>> iterator() {
return new EntriesIterator();
}
};
return entries;
}
private transient Set<K> keys;
@Override
public Set<K> keySet() {
if (keys == null) keys = new AbstractSet<K>() {
@Override
public int size() {
return map.size();
}
@Override
public Iterator<K> iterator() {
return new KeysIterator();
}
};
return keys;
}
private transient Collection<V> values;
@Override
public Collection<V> values() {
if (values == null) values = new AbstractCollection<V>() {
@Override
public int size() {
return map.size();
}
@Override
public Iterator<V> iterator() {
return new ValuesIterator();
}
};
return values;
}
private transient List<Entry<K, V>> entryList;
public List<Entry<K, V>> entryList() {
if (entryList == null) entryList = new AbstractList<Entry<K, V>>() {
@Override
public int size() {
return map.size();
}
@Override
public Entry<K, V> get(int index) {
return getEntry(index);
}
};
return entryList;
}
private transient List<K> keyList;
public List<K> keyList() {
if (keyList == null) keyList = new AbstractList<K>() {
@Override
public int size() {
return map.size();
}
@Override
public K get(int index) {
return getKey(index);
}
};
return keyList;
}
private transient List<V> valueList;
public List<V> valueList() {
if (valueList == null) valueList = new AbstractList<V>() {
@Override
public int size() {
return map.size();
}
@Override
public V get(int index) {
return getValue(index);
}
@Override
public V set(int index, V element) {
return getEntry(index).setValue(element);
}
};
return valueList;
}
// Creates swallow clone. Keys and values are not cloned.
@Override
public ListOrderedMap<K, V> clone() {
return new ListOrderedMap<K, V>(this);
}
static final class LinkedEntry<K, V> extends MapEntry<K, V> {
private static final long serialVersionUID = 1L;
private LinkedEntry<K, V> prev;
private LinkedEntry<K, V> next;
// Needed for serialization
public LinkedEntry() {
super(null, null);
}
public LinkedEntry(K key, V value) {
super(key, value);
}
public void remove() {
prev.next = next;
next.prev = prev;
}
public void insertBefore(LinkedEntry<K, V> entry) {
next = entry;
prev = entry.prev;
entry.prev = this;
prev.next = this;
}
public void moveBefore(LinkedEntry<K, V> entry) {
remove();
insertBefore(entry);
}
@Override
public String toString() {
return value != null ? value.toString() : "null";
}
}
abstract class OrderedMapIterator<E> implements Iterator<E> {
private LinkedEntry<K, V> curr, prev;
public OrderedMapIterator() {
super();
curr = header.next;
}
@Override
public boolean hasNext() {
return curr != header;
}
@Override
public void remove() {
if (prev == null) throw new IllegalStateException();
map.remove(prev.key);
prev.remove();
prev = null;
}
protected LinkedEntry<K, V> nextEntry() {
if (curr == header) throw new NoSuchElementException();
prev = curr;
curr = curr.next;
return prev;
}
}
final class EntriesIterator extends OrderedMapIterator<Map.Entry<K, V>> {
@Override
public Map.Entry<K, V> next() {
return nextEntry();
}
}
final class KeysIterator extends OrderedMapIterator<K> {
@Override
public K next() {
return nextEntry().key;
}
}
final class ValuesIterator extends OrderedMapIterator<V> {
@Override
public V next() {
return nextEntry().value;
}
}
static class MapEntry<K, V> implements Map.Entry<K, V>, Serializable {
private static final long serialVersionUID = 1L;
protected K key;
protected V value;
/**
* Creates new <tt>MapEntry</tt> instance with specified key and value.
* @param key key.
* @param value value.
*/
public MapEntry(K key, V value) {
super();
this.key = key;
this.value = value;
}
/**
* @return entry key.
*/
@Override
public K getKey() {
return key;
}
/**
* @return entry value.
*/
@Override
public V getValue() {
return value;
}
/**
* Sets new value for this entry. Underlying <tt>Map</tt> should reflect the changes to this entry.
* @param value new value.
* @return old value.
*/
@Override
public V setValue(V value) {
V old = this.value;
this.value = value;
return old;
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Map.Entry)) return false;
@SuppressWarnings("unchecked")
Map.Entry<K, V> entry = (Map.Entry<K, V>) o;
K k = entry.getKey();
if (k == key || (k != null && k.equals(key))) {
V v = entry.getValue();
return v == value || (v != null && v.equals(value));
}
return false;
}
@Override
public int hashCode() {
return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
}
@Override
public String toString() {
return key + "=" + value;
}
}
}