com.vladsch.flexmark.util.collection.OrderedMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of flexmark-util-collection Show documentation
Show all versions of flexmark-util-collection Show documentation
flexmark-java collection utility classes
The newest version!
package com.vladsch.flexmark.util.collection;
import com.vladsch.flexmark.util.collection.iteration.Indexed;
import com.vladsch.flexmark.util.collection.iteration.IndexedIterable;
import com.vladsch.flexmark.util.collection.iteration.IndexedIterator;
import com.vladsch.flexmark.util.collection.iteration.ReversibleIndexedIterator;
import com.vladsch.flexmark.util.collection.iteration.ReversibleIterable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class OrderedMap implements Map, Iterable> {
final @NotNull OrderedSet keySet;
private final @NotNull ArrayList valueList;
private final @Nullable CollectionHost host;
boolean inUpdate;
private @Nullable Indexed> indexedEntryProxy;
private @Nullable Indexed indexedValueProxy;
public OrderedMap() {
this(0, null);
}
public OrderedMap(int capacity) {
this(capacity, null);
}
public OrderedMap(@NotNull CollectionHost host) {
this(0, host);
}
public OrderedMap(int capacity, @Nullable CollectionHost host) {
this.valueList = new ArrayList<>(capacity);
this.host = host;
this.indexedEntryProxy = null;
this.indexedValueProxy = null;
this.keySet =
new OrderedSet<>(
capacity,
new CollectionHost() {
@Override
public void adding(int index, @Nullable K k, @Nullable Object v) {
OrderedMap.this.adding(index, k, v);
}
@Override
public Object removing(int index, @Nullable K k) {
return OrderedMap.this.removing(index, k);
}
@Override
public void clearing() {
OrderedMap.this.clearing();
}
@Override
public void addingNulls(int index) {
// can add anything, it will not be accessed, its a dummy holder
OrderedMap.this.addingNull(index);
}
@Override
public boolean skipHostUpdate() {
return inUpdate;
}
@Override
public int getIteratorModificationCount() {
return OrderedMap.this.getModificationCount();
}
});
}
public @NotNull Indexed> getIndexedEntryProxy() {
if (indexedEntryProxy != null) {
return indexedEntryProxy;
}
indexedEntryProxy =
new Indexed<>() {
@Override
public Map.Entry get(int index) {
return OrderedMap.this.getEntry(index);
}
@Override
public void set(int index, Map.Entry item) {
throw new UnsupportedOperationException();
}
@Override
public void removeAt(int index) {
OrderedMap.this.keySet.removeIndexHosted(index);
}
@Override
public int size() {
return OrderedMap.this.size();
}
@Override
public int modificationCount() {
return OrderedMap.this.getModificationCount();
}
};
return indexedEntryProxy;
}
public @NotNull Indexed getIndexedValueProxy() {
if (indexedValueProxy != null) {
return indexedValueProxy;
}
indexedValueProxy =
new Indexed<>() {
@Override
public V get(int index) {
return OrderedMap.this.getValue(index);
}
@Override
public void set(int index, V item) {
throw new UnsupportedOperationException();
}
@Override
public void removeAt(int index) {
OrderedMap.this.keySet.removeIndexHosted(index);
}
@Override
public int size() {
return OrderedMap.this.size();
}
@Override
public int modificationCount() {
return OrderedMap.this.getModificationCount();
}
};
return indexedValueProxy;
}
@NotNull
Map.Entry getEntry(int index) {
return new MapEntry<>(keySet.getValue(index), valueList.get(index));
}
public int getModificationCount() {
return keySet.getModificationCount();
}
void adding(int index, @NotNull K k, @NotNull Object v) {
if (v == null) {
throw new IllegalArgumentException();
}
if (host != null && !host.skipHostUpdate()) {
host.adding(index, k, v);
}
valueList.add((V) v);
}
void addingNull(int index) {
if (host != null && !host.skipHostUpdate()) {
host.addingNulls(index);
}
addNulls(index);
}
Object removing(int index, @NotNull K k) {
if (host != null && !host.skipHostUpdate()) {
host.removing(index, k);
}
return valueList.get(index);
}
void clearing() {
if (host != null && !host.skipHostUpdate()) {
host.clearing();
}
valueList.clear();
}
@Override
public int size() {
return keySet.size();
}
@Override
public boolean isEmpty() {
return keySet.isEmpty();
}
@Override
public boolean containsKey(@Nullable Object o) {
return keySet.contains(o);
}
@Override
public boolean containsValue(@Nullable Object o) {
int index = valueList.indexOf(o);
return keySet.isValidIndex(index);
}
private void addNulls(int index) {
if (index < valueList.size())
throw new IllegalArgumentException(
"addNulls(" + index + ") called when valueList size is " + valueList.size());
while (valueList.size() <= index) valueList.add(null);
}
@Override
public @Nullable V get(@Nullable Object o) {
int index = keySet.indexOf(o);
return index == -1 ? null : valueList.get(index);
}
@Override
public @Nullable V put(@NotNull K k, @NotNull V v) {
int index = keySet.indexOf(k);
if (index == -1) {
keySet.add(k, v);
return null;
}
V old = valueList.get(index);
valueList.set(index, v);
return old;
}
@Override
public @NotNull V remove(@Nullable Object o) {
return (V) keySet.removeHosted(o);
}
@Override
public void putAll(@NotNull Map extends K, ? extends V> map) {
for (Map.Entry extends K, ? extends V> entry : map.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
public void addAll(@NotNull Collection extends Map.Entry extends K, ? extends V>> entries) {
for (Map.Entry extends K, ? extends V> entry : entries) {
put(entry.getKey(), entry.getValue());
}
}
@Override
public void clear() {
keySet.clear();
}
@NotNull
@Override
public OrderedSet keySet() {
return keySet;
}
@NotNull
@Override
public Collection values() {
if (!keySet.isSparse()) {
return valueList;
}
List values = new ArrayList<>(keySet.size());
Iterator iterator = keySet.indexIterator();
while (iterator.hasNext()) {
values.add(valueList.get(iterator.next()));
}
return values;
}
public @Nullable V getValue(int index) {
if (!keySet.isValidIndex(index)) {
return null;
}
return valueList.get(index);
}
@NotNull
@Override
public OrderedSet> entrySet() {
// create it with inHostUpdate already set so we can populate it without callbacks
inUpdate = true;
OrderedSet> values =
new OrderedSet<>(keySet.size(), new EntryCollectionHost<>());
Iterator> iterator = entryIterator();
while (iterator.hasNext()) {
values.add(iterator.next());
}
// release it for host update
inUpdate = false;
return values;
}
public @NotNull List> entries() {
// create it with inHostUpdate already set so we can populate it without callbacks
List> values = new ArrayList<>();
Iterator> iterator = entryIterator();
while (iterator.hasNext()) {
values.add(iterator.next());
}
return values;
}
public @NotNull ReversibleIndexedIterator valueIterator() {
return new IndexedIterator<>(getIndexedValueProxy(), keySet.indexIterator());
}
public @NotNull ReversibleIndexedIterator keyIterator() {
return keySet.iterator();
}
public @NotNull ReversibleIndexedIterator> entryIterator() {
return new IndexedIterator<>(getIndexedEntryProxy(), keySet.indexIterator());
}
public @NotNull ReversibleIndexedIterator> reversedEntryIterator() {
return new IndexedIterator<>(getIndexedEntryProxy(), keySet.reversedIndexIterator());
}
public @NotNull ReversibleIterable valueIterable() {
return new IndexedIterable<>(getIndexedValueProxy(), keySet.indexIterable());
}
public @NotNull ReversibleIterable> entryIterable() {
return new IndexedIterable<>(getIndexedEntryProxy(), keySet.indexIterable());
}
public @NotNull ReversibleIterable> reversedEntryIterable() {
return new IndexedIterable<>(getIndexedEntryProxy(), keySet.reversedIndexIterable());
}
public @NotNull ReversibleIterable> reversedIterable() {
return reversedEntryIterable();
}
@NotNull
@Override
public ReversibleIndexedIterator> iterator() {
return entryIterator();
}
@Override
public void forEach(Consumer super Entry> consumer) {
Iterator> iterator = iterator();
while (iterator.hasNext()) {
consumer.accept(iterator.next());
}
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object == null || getClass() != object.getClass()) {
return false;
}
OrderedMap, ?> set = (OrderedMap, ?>) object;
if (size() != set.size()) {
return false;
}
return entrySet().equals(set.entrySet());
}
@Override
public int hashCode() {
int result = keySet.hashCode();
result = 31 * result + valueList.hashCode();
return result;
}
private class EntryCollectionHost
implements CollectionHost> {
@Override
public void adding(int index, @Nullable Entry entry, @Nullable Object v) {
OrderedMap.this.keySet.add(entry.getKey(), entry.getValue());
}
@Override
public Object removing(int index, @Nullable Entry entry) {
OrderedMap.this.keySet.removeIndex(index);
return entry;
}
@Override
public void clearing() {
OrderedMap.this.keySet.clear();
}
@Override
public void addingNulls(int index) {
OrderedMap.this.keySet.addNulls(index);
}
@Override
public boolean skipHostUpdate() {
return inUpdate;
}
@Override
public int getIteratorModificationCount() {
return OrderedMap.this.getModificationCount();
}
}
}