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

com.rapiddweller.common.OrderedMap Maven / Gradle / Ivy

Go to download

'rapiddweller Common' is an open source Java library forked from Databene Commons by Volker Bergmann. It provides extensions to the Java core library by utility classes, abstract concepts and concrete implementations.

There is a newer version: 2.0.1-jdk-11
Show newest version
/*
 * Copyright (C) 2004-2015 Volker Bergmann ([email protected]).
 * All rights reserved.
 *
 * 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 com.rapiddweller.common;

import com.rapiddweller.common.collection.ListBasedSet;
import com.rapiddweller.common.collection.MapEntry;
import com.rapiddweller.common.collection.MapProxy;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Map implementation that tracks the order in which elements where added
 * and returns them in that order by the values() method.
 * This is useful for all cases in which elements will be queried by a key
 * and processed but need to be stored in the original order.
 * Created: 06.01.2007 09:04:17
 *
 * @param  the key type
 * @param  the value type
 * @author Volker Bergmann
 */
public class OrderedMap implements Map, Serializable {

  private static final long serialVersionUID = -6081918861041975388L;

  private final Map keyIndices;
  /**
   * The Values.
   */
  protected List values;

  // constructors ----------------------------------------------------------------------------------------------------

  /**
   * Instantiates a new Ordered map.
   */
  public OrderedMap() {
    keyIndices = new HashMap<>();
    values = new ArrayList<>();
  }

  /**
   * Instantiates a new Ordered map.
   *
   * @param initialCapacity the initial capacity
   */
  public OrderedMap(int initialCapacity) {
    keyIndices = new HashMap<>(initialCapacity);
    values = new ArrayList<>(initialCapacity);
  }

  /**
   * Instantiates a new Ordered map.
   *
   * @param initialCapacity the initial capacity
   * @param loadFactor      the load factor
   */
  public OrderedMap(int initialCapacity, float loadFactor) {
    keyIndices = new HashMap<>(initialCapacity, loadFactor);
    values = new ArrayList<>(initialCapacity);
  }

  /**
   * Instantiates a new Ordered map.
   *
   * @param source the source
   */
  public OrderedMap(Map source) {
    this(source.size());
    for (Entry entry : source.entrySet()) {
      put(entry.getKey(), entry.getValue());
    }
  }


  // custom interface ------------------------------------------------------------------------------------------------

  /**
   * Gets entry.
   *
   * @param key the key
   * @return the entry
   */
  public Map.Entry getEntry(K key) {
    if (containsKey(key)) {
      return new MapEntry<>(key, get(key));
    } else {
      return null;
    }
  }


  // Map interface implementation ------------------------------------------------------------------------------------

  @Override
  public int size() {
    return values.size();
  }

  @Override
  public boolean isEmpty() {
    return values.isEmpty();
  }

  @Override
  public boolean containsKey(Object key) {
    return keyIndices.containsKey(key);
  }

  @Override
  public boolean containsValue(Object value) {
    return values.contains(value);
  }

  @Override
  public V get(Object key) {
    Integer index = keyIndices.get(key);
    if (index == null) {
      return null;
    }
    return values.get(index);
  }

  @Override
  public V put(K key, V value) {
    Integer index = keyIndices.get(key);
    if (index != null) {
      return values.set(index, value);
    } else {
      keyIndices.put(key, values.size());
      values.add(value);
      return null;
    }
  }

  @Override
  public V remove(Object key) {
    Integer index = keyIndices.remove(key);
    if (index != null) {
      V oldValue = values.get(index);
      values.remove((int) index);
      for (Entry entry : keyIndices.entrySet()) {
        int entryIndex = entry.getValue();
        if (entryIndex > index) {
          entry.setValue(entryIndex - 1);
        }
      }
      return oldValue;
    } else {
      return null;
    }
  }

  @Override
  public void putAll(Map t) {
    for (Map.Entry entry : t.entrySet()) {
      put(entry.getKey(), entry.getValue());
    }
  }

  @Override
  public void clear() {
    keyIndices.clear();
    values.clear();
  }

  @Override
  public Set keySet() {
    List tmp = new ArrayList<>(values.size());
    // set the used array size by adding nulls
    for (int i = 0; i < values.size(); i++) {
      tmp.add(null);
    }
    // set the array elements themselves
    for (Entry entry : keyIndices.entrySet()) {
      tmp.set(entry.getValue(), entry.getKey());
    }
    return new ListBasedSet<>(tmp);
  }

  @Override
  public List values() {
    return new ArrayList<>(values);
  }

  @Override
  @SuppressWarnings("unchecked")
  public Set> entrySet() {
    Map.Entry[] tmp = new Map.Entry[values.size()];
    for (Map.Entry entry : keyIndices.entrySet()) {
      Integer index = entry.getValue();
      tmp[index] = new ProxyEntry(entry.getKey(), index);
    }
    return new ListBasedSet<>(tmp);
  }

  // List/Vector interface -------------------------------------------------------------------------------------------

  /**
   * Value at v.
   *
   * @param index the index
   * @return the v
   */
  public V valueAt(int index) {
    return values.get(index);
  }

  /**
   * Index of value int.
   *
   * @param value the value
   * @return the int
   */
  public int indexOfValue(V value) {
    return values.indexOf(value);
  }

  /**
   * Returns an array containing all of the values in this map in proper sequence.
   * Obeys the general contract of the Collection.toArray method.
   *
   * @return an array containing all of the elements in this list in proper sequence.
   */
  public Object[] toArray() {
    return values.toArray();
  }

  /**
   * Returns an array containing all of the values in this map in proper sequence;
   * the runtime type of the returned array is that of the specified array.
   * Obeys the general contract of the Collection.toArray(Object[]) method.
   *
   * @param  the component type of the result array
   * @param a   the array into which the elements of this list are to be stored, if it is big enough; otherwise, a new array of the same runtime type is allocated for this purpose.
   * @return an array containing the values of this map.
   * @throws ArrayStoreException  if the runtime type of the specified array is not a supertype of the runtime type of every element in this list.
   * @throws NullPointerException - if the specified array is null.
   */
  public  T[] toArray(T[] a) {
    return values.toArray(a);
  }

  // specific interface ----------------------------------------------------------------------------------------------

  /**
   * Internal values list.
   *
   * @return the list
   */
  public List internalValues() {
    return values;
  }

  /**
   * Equals ignore order boolean.
   *
   * @param that the that
   * @return the boolean
   */
  public boolean equalsIgnoreOrder(Map that) {
    if (this == that) {
      return true;
    }
    if (this.size() != that.size()) {
      return false;
    }
    for (Map.Entry entry : that.entrySet()) {
      K key = entry.getKey();
      if (!this.containsKey(key)) {
        return false;
      }
      if (!NullSafeComparator.equals(this.get(key), that.get(key))) {
        return false;
      }
    }
    return true;
  }

  private class ProxyEntry implements Map.Entry {

    private final K key;
    private final int index;

    /**
     * Instantiates a new Proxy entry.
     *
     * @param key   the key
     * @param index the index
     */
    public ProxyEntry(K key, int index) {
      this.key = key;
      this.index = index;
    }

    @Override
    public K getKey() {
      return key;
    }

    @Override
    public V getValue() {
      return OrderedMap.this.values.get(index);
    }

    @Override
    public V setValue(V value) {
      return OrderedMap.this.values.set(index, value);
    }

    @Override
    public String toString() {
      return String.valueOf(key) + '=' + getValue();
    }
  }

  // java.lang.Object overrides --------------------------------------------------------------------------------------

  @SuppressWarnings("rawtypes")
  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || !(o instanceof Map)) {
      return false;
    }
    while (o instanceof MapProxy) {
      o = ((MapProxy) o).getRealMap();
    }
    final OrderedMap that = (OrderedMap) o;
    return (this.values.equals(that.values) && this.keyIndices.equals(that.keyIndices));
  }

  @Override
  public int hashCode() {
    return keyIndices.hashCode() * 29 + values.hashCode();
  }

  @Override
  public String toString() {
    ListBasedSet> entries = (ListBasedSet>) entrySet();
    StringBuilder buffer = new StringBuilder("{");
    if (entries.size() > 0) {
      buffer.append(entries.get(0));
    }
    for (int i = 1; i < entries.size(); i++) {
      buffer.append(", ").append(entries.get(i));
    }
    buffer.append('}');
    return buffer.toString();
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy