![JAR search and dependency download from the Maven repository](/logo.png)
jetbrick.collection.ListOrderedMap Maven / Gradle / Ivy
/**
* Copyright 2013-2016 Guoqiang Chen, Shanghai, China. All rights reserved.
*
* Author: Guoqiang Chen
* Email: [email protected]
* 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 extends AbstractMap implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private final Map> map;
private LinkedEntry header;
public ListOrderedMap() {
map = new HashMap>();
createHeader();
}
public ListOrderedMap(int initialCapacity) {
map = new HashMap>(initialCapacity);
createHeader();
}
public ListOrderedMap(int initialCapacity, float loadFactor) {
map = new HashMap>(initialCapacity, loadFactor);
createHeader();
}
public ListOrderedMap(Map extends K, ? extends V> m) {
this();
putAll(m);
}
private void createHeader() {
header = new LinkedEntry();
header.prev = header.next = header;
}
// OrderedMap interface
public Entry getEntry(int index) {
if (index < 0 || index >= size()) {
throw new IndexOutOfBoundsException();
}
LinkedEntry 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 put(int index, K key, V value) {
if (index < 0 || index > size()) throw new IndexOutOfBoundsException();
LinkedEntry 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 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(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 remove(int index) {
Entry entry = getEntry(index);
remove(entry.getKey());
return entry;
}
public Iterator> iterator() {
return new EntriesIterator();
}
public Entry[] toArray() {
int size = size();
@SuppressWarnings("unchecked")
Entry[] entries = new LinkedEntry[size];
LinkedEntry 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 entry = map.get(key);
return entry != null ? entry.value : null;
}
@Override
public V put(K key, V value) {
LinkedEntry entry = map.get(key);
if (entry != null) {
V old = entry.value;
entry.value = value;
return old;
} else {
entry = new LinkedEntry(key, value);
entry.insertBefore(header);
map.put(key, entry);
return null;
}
}
@Override
public V remove(Object key) {
LinkedEntry 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> entries;
@Override
public Set> entrySet() {
if (entries == null) entries = new AbstractSet>() {
@Override
public int size() {
return map.size();
}
@Override
public Iterator> iterator() {
return new EntriesIterator();
}
};
return entries;
}
private transient Set keys;
@Override
public Set keySet() {
if (keys == null) keys = new AbstractSet() {
@Override
public int size() {
return map.size();
}
@Override
public Iterator iterator() {
return new KeysIterator();
}
};
return keys;
}
private transient Collection values;
@Override
public Collection values() {
if (values == null) values = new AbstractCollection() {
@Override
public int size() {
return map.size();
}
@Override
public Iterator iterator() {
return new ValuesIterator();
}
};
return values;
}
private transient List> entryList;
public List> entryList() {
if (entryList == null) entryList = new AbstractList>() {
@Override
public int size() {
return map.size();
}
@Override
public Entry get(int index) {
return getEntry(index);
}
};
return entryList;
}
private transient List keyList;
public List keyList() {
if (keyList == null) keyList = new AbstractList() {
@Override
public int size() {
return map.size();
}
@Override
public K get(int index) {
return getKey(index);
}
};
return keyList;
}
private transient List valueList;
public List valueList() {
if (valueList == null) valueList = new AbstractList() {
@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 clone() {
return new ListOrderedMap(this);
}
static final class LinkedEntry extends MapEntry {
private static final long serialVersionUID = 1L;
private LinkedEntry prev;
private LinkedEntry 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 entry) {
next = entry;
prev = entry.prev;
entry.prev = this;
prev.next = this;
}
public void moveBefore(LinkedEntry entry) {
remove();
insertBefore(entry);
}
@Override
public String toString() {
return value != null ? value.toString() : "null";
}
}
abstract class OrderedMapIterator implements Iterator {
private LinkedEntry 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 nextEntry() {
if (curr == header) throw new NoSuchElementException();
prev = curr;
curr = curr.next;
return prev;
}
}
final class EntriesIterator extends OrderedMapIterator> {
@Override
public Map.Entry next() {
return nextEntry();
}
}
final class KeysIterator extends OrderedMapIterator {
@Override
public K next() {
return nextEntry().key;
}
}
final class ValuesIterator extends OrderedMapIterator {
@Override
public V next() {
return nextEntry().value;
}
}
static class MapEntry implements Map.Entry, Serializable {
private static final long serialVersionUID = 1L;
protected K key;
protected V value;
/**
* Creates new MapEntry 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 Map 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 entry = (Map.Entry) 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;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy