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

org.eclipse.mat.collect.HashMapIntObject Maven / Gradle / Ivy

There is a newer version: 2.1
Show newest version
/**
 * ****************************************************************************
 * Copyright (c) 2008 SAP AG.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * SAP AG - initial API and implementation
 * *****************************************************************************
 */
package org.eclipse.mat.collect;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Iterator;
import java.util.NoSuchElementException;

public final class HashMapIntObject implements Serializable {
  public interface Entry {
    int getKey();

    E getValue();
  }

  private static final long serialVersionUID = 2L;

  private int capacity;
  private int step;
  private int limit;
  private int size;
  private transient boolean[] used;
  private transient int[] keys;
  private transient E[] values;

  public HashMapIntObject() {
    this(10);
  }

  public HashMapIntObject(int initialCapacity) {
    init(initialCapacity);
  }

  public E put(int key, E value) {
    if (size == limit) resize(capacity << 1);

    int hash = (key & Integer.MAX_VALUE) % capacity;
    while (used[hash]) {
      if (keys[hash] == key) {
        E oldValue = values[hash];
        values[hash] = value;
        return oldValue;
      }
      hash = (hash + step) % capacity;
    }
    used[hash] = true;
    keys[hash] = key;
    values[hash] = value;
    size++;
    return null;
  }

  public E remove(int key) {
    int hash = (key & Integer.MAX_VALUE) % capacity;
    while (used[hash]) {
      if (keys[hash] == key) {
        E oldValue = values[hash];
        used[hash] = false;
        size--;
        // Re-hash all follow-up entries anew; Do not fiddle with the
        // capacity limit (75 %) otherwise this code may loop forever
        hash = (hash + step) % capacity;
        while (used[hash]) {
          key = keys[hash];
          used[hash] = false;
          int newHash = (key & Integer.MAX_VALUE) % capacity;
          while (used[newHash]) {
            newHash = (newHash + step) % capacity;
          }
          used[newHash] = true;
          keys[newHash] = key;
          values[newHash] = values[hash];
          hash = (hash + step) % capacity;
        }
        return oldValue;
      }
      hash = (hash + step) % capacity;
    }
    return null;
  }

  public boolean containsKey(int key) {
    int hash = (key & Integer.MAX_VALUE) % capacity;
    while (used[hash]) {
      if (keys[hash] == key) {
        return true;
      }
      hash = (hash + step) % capacity;
    }
    return false;
  }

  public E get(int key) {
    int hash = (key & Integer.MAX_VALUE) % capacity;
    while (used[hash]) {
      if (keys[hash] == key) {
        return values[hash];
      }
      hash = (hash + step) % capacity;
    }
    return null;
  }

  public int[] getAllKeys() {
    int[] array = new int[size];
    int j = 0;
    for (int i = 0; i < used.length; i++) {
      if (used[i]) {
        array[j++] = keys[i];
      }
    }
    return array;
  }

  public Object[] getAllValues() {
    Object[] array = new Object[size];
    int index = 0;
    for (int ii = 0; ii < used.length; ii++) {
      if (used[ii]) array[index++] = values[ii];
    }
    return array;
  }

  @SuppressWarnings("unchecked") public  T[] getAllValues(T[] a) {
    if (a.length < size) a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);

    int index = 0;
    for (int ii = 0; ii < used.length; ii++) {
      if (used[ii]) a[index++] = (T) values[ii];
    }

    if (a.length > size) a[size] = null;
    return a;
  }

  public int size() {
    return size;
  }

  public boolean isEmpty() {
    return size() == 0;
  }

  public void clear() {
    size = 0;
    used = new boolean[capacity];
  }

  public IteratorInt keys() {
    return new IteratorInt() {
      int n = 0;
      int i = -1;

      public boolean hasNext() {
        return n < size;
      }

      public int next() throws NoSuchElementException {
        while (++i < used.length) {
          if (used[i]) {
            n++;
            return keys[i];
          }
        }
        throw new NoSuchElementException();
      }
    };
  }

  public Iterator values() {
    return new Iterator() {
      int n = 0;
      int i = -1;

      public boolean hasNext() {
        return n < size;
      }

      public E next() throws NoSuchElementException {
        while (++i < used.length) {
          if (used[i]) {
            n++;
            return values[i];
          }
        }
        throw new NoSuchElementException();
      }

      public void remove() throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
      }
    };
  }

  public Iterator> entries() {
    return new Iterator>() {
      int n = 0;
      int i = -1;

      public boolean hasNext() {
        return n < size;
      }

      public Entry next() throws NoSuchElementException {
        while (++i < used.length) {
          if (used[i]) {
            n++;
            return new Entry() {
              public int getKey() {
                return keys[i];
              }

              public E getValue() {
                return values[i];
              }
            };
          }
        }
        throw new NoSuchElementException();
      }

      public void remove() throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
      }
    };
  }

  @SuppressWarnings("unchecked") private void init(int initialCapacity) {
    capacity = PrimeFinder.findNextPrime(initialCapacity);
    step = Math.max(1, PrimeFinder.findPrevPrime(initialCapacity / 3));
    limit = (int) (capacity * 0.75);
    clear();
    keys = new int[capacity];
    // This cast is ok as long as nobody assigns the field values to a field
    // of type [] (values is of type Object[] and an assignment would
    // lead to a ClassCastException). This cast here is performed to extract
    // the array elements later without additional casts in the other calls.
    values = (E[]) new Object[capacity];
  }

  private void resize(int newCapacity) {
    int oldSize = size;
    boolean[] oldUsed = used;
    int[] oldKeys = keys;
    E[] oldValues = values;
    init(newCapacity);
    int key, hash;
    for (int i = 0; i < oldUsed.length; i++) {
      if (oldUsed[i]) {
        key = oldKeys[i];
        hash = (key & Integer.MAX_VALUE) % capacity;
        while (used[hash]) {
          hash = (hash + step) % capacity;
        }
        used[hash] = true;
        keys[hash] = key;
        values[hash] = oldValues[i];
      }
    }
    size = oldSize;
  }

  private void writeObject(ObjectOutputStream stream) throws IOException {
    stream.defaultWriteObject();
    for (int ii = 0; ii < used.length; ii++) {
      if (used[ii]) {
        stream.writeInt(keys[ii]);
        stream.writeObject(values[ii]);
      }
    }
  }

  @SuppressWarnings("unchecked") private void readObject(ObjectInputStream stream)
      throws IOException, ClassNotFoundException {
    stream.defaultReadObject();

    // compat: serialized maps could contain old step factor
    step = Math.max(1, PrimeFinder.findPrevPrime(capacity / 3));

    used = new boolean[capacity];
    keys = new int[capacity];
    values = (E[]) new Object[capacity];

    for (int ii = 0; ii < size; ii++)
      putQuick(stream.readInt(), (E) stream.readObject());
  }

  private void putQuick(int key, E value) {
    int hash = (key & Integer.MAX_VALUE) % capacity;
    while (used[hash]) {
      if (keys[hash] == key) {
        values[hash] = value;
        return;
      }
      hash = (hash + step) % capacity;
    }
    used[hash] = true;
    keys[hash] = key;
    values[hash] = value;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy