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

com.vladsch.flexmark.util.collection.OrderedMap Maven / Gradle / Ivy

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 map) {
    for (Map.Entry entry : map.entrySet()) {
      put(entry.getKey(), entry.getValue());
    }
  }

  public void addAll(@NotNull Collection> entries) {
    for (Map.Entry 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> 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();
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy