A set acts like array. : Set « Collections Data Structure « Java






A set acts like array.

      
/*
 * Copyright 2004-2010 the Seasar Foundation and the Others.
 *
 * 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 org.slim3.util;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Array;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

/**
 * A set acts like array.
 * 
 * @author higa
 * @param <E>
 *            the element type
 * @since 1.0.0
 */
public class ArraySet<E> extends AbstractSet<E> implements Set<E>, Cloneable,
    java.io.Serializable {

  static final long serialVersionUID = -5024744406713321676L;

  private transient ArrayMap<E, Object> map;

  // Dummy value to associate with an Object in the backing Map
  private static final Object PRESENT = new Object();

  /**
   * Constructor.
   */
  public ArraySet() {
    map = new ArrayMap<E, Object>();
  }

  /**
   * Constructor.
   * 
   * @param c
   *            the collection whose elements are to be placed into this set.
   * @throws NullPointerException
   *             if the specified collection is null.
   */
  public ArraySet(Collection<? extends E> c) throws NullPointerException {
    if (c == null) {
      throw new NullPointerException("The c parameter must not be null.");
    }
    map = new ArrayMap<E, Object>(Math.max((int) (c.size() / .75f) + 1, 16));
    addAll(c);
  }

  /**
   * Constructor.
   * 
   * @param initialCapacity
   *            the initial capacity of the hash table.
   * @throws IllegalArgumentException
   *             if the initial capacity is less than zero.
   */
  public ArraySet(int initialCapacity) {
    map = new ArrayMap<E, Object>(initialCapacity);
  }

  /**
   * Returns an element specified by the index.
   * 
   * @param index
   *            the index
   * @return an element
   */
  public E get(int index) {
    return map.getKey(index);
  }

  /**
   * Returns an iterator over the elements in this set. The elements are
   * returned in no particular order.
   * 
   * @return an Iterator over the elements in this set.
   * @see ConcurrentModificationException
   */
  @Override
  public Iterator<E> iterator() {
    return map.keySet().iterator();
  }

  /**
   * Returns the number of elements in this set (its cardinality).
   * 
   * @return the number of elements in this set (its cardinality).
   */
  @Override
  public int size() {
    return map.size();
  }

  /**
   * Returns <tt>true</tt> if this set contains no elements.
   * 
   * @return <tt>true</tt> if this set contains no elements.
   */
  @Override
  public boolean isEmpty() {
    return map.isEmpty();
  }

  /**
   * Returns <tt>true</tt> if this set contains the specified element.
   * 
   * @param o
   *            element whose presence in this set is to be tested.
   * @return <tt>true</tt> if this set contains the specified element.
   */
  @Override
  public boolean contains(Object o) {
    return map.containsKey(o);
  }

  /**
   * Adds the specified element to this set if it is not already present.
   * 
   * @param o
   *            element to be added to this set.
   * @return <tt>true</tt> if the set did not already contain the specified
   *         element.
   */
  @Override
  public boolean add(E o) {
    return map.put(o, PRESENT) == null;
  }

  /**
   * Removes the specified element from this set if it is present.
   * 
   * @param o
   *            object to be removed from this set, if present.
   * @return <tt>true</tt> if the set contained the specified element.
   */
  @Override
  public boolean remove(Object o) {
    return map.remove(o) == PRESENT;
  }

  /**
   * Removes all of the elements from this set.
   */
  @Override
  public void clear() {
    map.clear();
  }

  /**
   * Returns a shallow copy of this <tt>HashSet</tt> instance: the elements
   * themselves are not cloned.
   * 
   * @return a shallow copy of this set.
   */
  @SuppressWarnings("unchecked")
  @Override
  public Object clone() {
    try {
      ArraySet<E> newSet = (ArraySet<E>) super.clone();
      newSet.map = (ArrayMap<E, Object>) map.clone();
      return newSet;
    } catch (CloneNotSupportedException e) {
      throw new InternalError();
    }
  }

  /**
   * Save the state of this <tt>HashSet</tt> instance to a stream (that is,
   * serialize this set).
   * 
   * @serialData The capacity of the backing <tt>HashMap</tt> instance (int),
   *             and its load factor (float) are emitted, followed by the size
   *             of the set (the number of elements it contains) (int),
   *             followed by all of its elements (each an Object) in no
   *             particular order.
   */
  private void writeObject(java.io.ObjectOutputStream s)
      throws java.io.IOException {
    s.defaultWriteObject();
    s.writeInt(map.size());
    for (Iterator<E> i = map.keySet().iterator(); i.hasNext();) {
      s.writeObject(i.next());
    }
  }

  /**
   * Reconstitute the <tt>HashSet</tt> instance from a stream (that is,
   * deserialize it).
   */
  @SuppressWarnings("unchecked")
  private void readObject(java.io.ObjectInputStream s)
      throws java.io.IOException, ClassNotFoundException {
    // Read in any hidden serialization magic
    s.defaultReadObject();
    int size = s.readInt();
    map = new ArrayMap<E, Object>(size);
    for (int i = 0; i < size; i++) {
      E e = (E) s.readObject();
      map.put(e, PRESENT);
    }
  }
}

class ArrayMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Cloneable,
    Externalizable {

  private static final long serialVersionUID = 1L;

  /**
   * The default initial capacity.
   */
  protected static final int INITIAL_CAPACITY = 17;

  /**
   * The default load factor.
   */
  protected static final float LOAD_FACTOR = 0.75f;

  /**
   * The threshold to extend the capacity.
   */
  protected transient int threshold;

  /**
   * The map table.
   */
  protected transient Entry<K, V>[] mapTable;

  /**
   * The list table.
   */
  protected transient Entry<K, V>[] listTable;

  /**
   * The number of entries.
   */
  protected transient int size = 0;

  /**
   * The set of entries.
   */
  protected transient Set<Map.Entry<K, V>> entrySet = null;

  /**
   * Constructor.
   */
  public ArrayMap() {
    this(INITIAL_CAPACITY);
  }

  /**
   * Constructor.
   * 
   * @param initialCapacity
   *            the initial capacity
   */
  public ArrayMap(int initialCapacity) {
    if (initialCapacity <= 0) {
      initialCapacity = INITIAL_CAPACITY;
    }
    mapTable = createArray(initialCapacity);
    listTable = createArray(initialCapacity);
    threshold = (int) (initialCapacity * LOAD_FACTOR);
  }

  /**
   * Constructor.
   * 
   * @param map
   *            other map
   */
  public ArrayMap(Map<? extends K, ? extends V> map) {
    this((int) (map.size() / LOAD_FACTOR) + 1);
    putAll(map);
  }

  @Override
  public final int size() {
    return size;
  }

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

  @Override
  public final boolean containsValue(Object value) {
    return indexOf(value) >= 0;
  }

  /**
   * Returns the index in the list table.
   * 
   * @param value
   *            the value
   * @return the index
   */
  public final int indexOf(Object value) {
    if (value != null) {
      for (int i = 0; i < size; i++) {
        if (value.equals(listTable[i].value)) {
          return i;
        }
      }
    } else {
      for (int i = 0; i < size; i++) {
        if (listTable[i].value == null) {
          return i;
        }
      }
    }
    return -1;
  }

  @Override
  public boolean containsKey(Object key) {
    Entry<K, V>[] tbl = mapTable;
    if (key != null) {
      int hashCode = key.hashCode();
      int index = (hashCode & 0x7FFFFFFF) % tbl.length;
      for (Entry<K, V> e = tbl[index]; e != null; e = e.next) {
        if (e.hashCode == hashCode && key.equals(e.key)) {
          return true;
        }
      }
    } else {
      for (Entry<K, V> e = tbl[0]; e != null; e = e.next) {
        if (e.key == null) {
          return true;
        }
      }
    }
    return false;
  }

  @Override
  public V get(Object key) {
    Entry<K, V>[] tbl = mapTable;
    if (key != null) {
      int hashCode = key.hashCode();
      int index = (hashCode & 0x7FFFFFFF) % tbl.length;
      for (Entry<K, V> e = tbl[index]; e != null; e = e.next) {
        if (e.hashCode == hashCode && key.equals(e.key)) {
          return e.value;
        }
      }
    } else {
      for (Entry<K, V> e = tbl[0]; e != null; e = e.next) {
        if (e.key == null) {
          return e.value;
        }
      }
    }
    return null;
  }

  /**
   * Returns the value for the index.
   * 
   * @param index
   *            the index
   * @return the value
   */
  public final V get(int index) {
    return getEntry(index).value;
  }

  /**
   * Returns the key for the index.
   * 
   * @param index
   *            the index
   * @return the key
   */
  public final K getKey(int index) {
    return getEntry(index).key;
  }

  /**
   * Returns the entry for the index.
   * 
   * @param index
   *            the index
   * @return the entry
   */
  public final Entry<K, V> getEntry(int index) {
    if (index >= size) {
      throw new IndexOutOfBoundsException("Index:" + index + ", Size:"
          + size);
    }
    return listTable[index];
  }

  @Override
  public V put(K key, V value) {
    int hashCode = 0;
    int index = 0;

    if (key != null) {
      hashCode = key.hashCode();
      index = (hashCode & 0x7FFFFFFF) % mapTable.length;
      for (Entry<K, V> e = mapTable[index]; e != null; e = e.next) {
        if ((e.hashCode == hashCode) && key.equals(e.key)) {
          return swapValue(e, value);
        }
      }
    } else {
      for (Entry<K, V> e = mapTable[0]; e != null; e = e.next) {
        if (e.key == null) {
          return swapValue(e, value);
        }
      }
    }
    ensureCapacity();
    index = (hashCode & 0x7FFFFFFF) % mapTable.length;
    Entry<K, V> e = new Entry<K, V>(hashCode, key, value, mapTable[index]);
    mapTable[index] = e;
    listTable[size++] = e;
    return null;
  }

  /**
   * Sets the value for the index.
   * 
   * @param index
   *            the index
   * @param value
   *            the value
   */
  public final void set(int index, V value) {
    getEntry(index).setValue(value);
  }

  @Override
  public V remove(Object key) {
    Entry<K, V> e = removeMap(key);
    if (e != null) {
      V value = e.value;
      removeList(indexOf(e));
      e.clear();
      return value;
    }
    return null;
  }

  /**
   * Removes the entry for the index.
   * 
   * @param index
   *            the index
   * @return the removed value
   */
  public final V remove(int index) {
    Entry<K, V> e = removeList(index);
    V value = e.value;
    removeMap(e.key);
    e.value = null;
    return value;
  }

  @Override
  public void putAll(Map<? extends K, ? extends V> map) {
    for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = map
        .entrySet().iterator(); i.hasNext();) {
      Map.Entry<? extends K, ? extends V> e = i.next();
      put(e.getKey(), e.getValue());
    }
  }

  @Override
  public final void clear() {
    for (int i = 0; i < mapTable.length; i++) {
      mapTable[i] = null;
    }
    for (int i = 0; i < listTable.length; i++) {
      listTable[i] = null;
    }
    size = 0;
  }

  /**
   * Converts this object to an array.
   * 
   * @return an array
   */
  public final Object[] toArray() {
    Object[] array = new Object[size];
    for (int i = 0; i < array.length; i++) {
      array[i] = get(i);
    }
    return array;
  }

  /**
   * Converts this object to an array.
   * 
   * @param proto
   *            the prototype
   * @return an array
   */
  public final Object[] toArray(final Object proto[]) {
    Object[] array = proto;
    if (proto.length < size) {
      array = (Object[]) Array.newInstance(proto.getClass()
          .getComponentType(), size);
    }
    for (int i = 0; i < array.length; i++) {
      array[i] = get(i);
    }
    if (array.length > size) {
      array[size] = null;
    }
    return array;
  }

  @Override
  @SuppressWarnings("unchecked")
  public final boolean equals(Object o) {
    if (!getClass().isInstance(o)) {
      return false;
    }
    ArrayMap<K, V> e = (ArrayMap) o;
    if (size != e.size) {
      return false;
    }
    for (int i = 0; i < size; i++) {
      if (!listTable[i].equals(e.listTable[i])) {
        return false;
      }
    }
    return true;
  }

  @Override
  public final Set<Map.Entry<K, V>> entrySet() {
    if (entrySet == null) {
      entrySet = new AbstractSet<Map.Entry<K, V>>() {
        @Override
        public Iterator<Map.Entry<K, V>> iterator() {
          return new ArrayMapIterator();
        }

        @Override
        @SuppressWarnings("unchecked")
        public boolean contains(Object o) {
          if (!(o instanceof Entry)) {
            return false;
          }
          Entry<K, V> entry = (Entry<K, V>) o;
          int index = (entry.hashCode & 0x7FFFFFFF) % mapTable.length;
          for (Entry<K, V> e = mapTable[index]; e != null; e = e.next) {
            if (e.equals(entry)) {
              return true;
            }
          }
          return false;
        }

        @Override
        @SuppressWarnings("unchecked")
        public boolean remove(Object o) {
          if (!(o instanceof Entry)) {
            return false;
          }
          Entry<K, V> entry = (Entry) o;
          return ArrayMap.this.remove(entry.key) != null;
        }

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

        @Override
        public void clear() {
          ArrayMap.this.clear();
        }
      };
    }
    return entrySet;
  }

  public final void writeExternal(final ObjectOutput out) throws IOException {
    out.writeInt(listTable.length);
    out.writeInt(size);
    for (int i = 0; i < size; i++) {
      out.writeObject(listTable[i].key);
      out.writeObject(listTable[i].value);
    }
  }

  @SuppressWarnings("unchecked")
  public final void readExternal(final ObjectInput in) throws IOException,
      ClassNotFoundException {

    int num = in.readInt();
    mapTable = createArray(num);
    listTable = createArray(num);
    threshold = (int) (num * LOAD_FACTOR);
    int size = in.readInt();
    for (int i = 0; i < size; i++) {
      K key = (K) in.readObject();
      V value = (V) in.readObject();
      put(key, value);
    }
  }

  @Override
  public Object clone() {
    ArrayMap<K, V> copy = new ArrayMap<K, V>();
    copy.threshold = threshold;
    copy.mapTable = mapTable;
    copy.listTable = listTable;
    copy.size = size;
    return copy;
  }

  private final int indexOf(final Entry<K, V> entry) {
    for (int i = 0; i < size; i++) {
      if (listTable[i] == entry) {
        return i;
      }
    }
    return -1;
  }

  private final Entry<K, V> removeMap(Object key) {
    int hashCode = 0;
    int index = 0;

    if (key != null) {
      hashCode = key.hashCode();
      index = (hashCode & 0x7FFFFFFF) % mapTable.length;
      for (Entry<K, V> e = mapTable[index], prev = null; e != null; prev = e, e = e.next) {
        if ((e.hashCode == hashCode) && key.equals(e.key)) {
          if (prev != null) {
            prev.next = e.next;
          } else {
            mapTable[index] = e.next;
          }
          return e;
        }
      }
    } else {
      for (Entry<K, V> e = mapTable[index], prev = null; e != null; prev = e, e = e.next) {
        if ((e.hashCode == hashCode) && e.key == null) {
          if (prev != null) {
            prev.next = e.next;
          } else {
            mapTable[index] = e.next;
          }
          return e;
        }
      }
    }
    return null;
  }

  private final Entry<K, V> removeList(int index) {
    Entry<K, V> e = listTable[index];
    int numMoved = size - index - 1;
    if (numMoved > 0) {
      System.arraycopy(listTable, index + 1, listTable, index, numMoved);
    }
    listTable[--size] = null;
    return e;
  }

  private final void ensureCapacity() {
    if (size >= threshold) {
      Entry<K, V>[] oldTable = listTable;
      int newCapacity = oldTable.length * 2 + 1;
      Entry<K, V>[] newMapTable = createArray(newCapacity);
      Entry<K, V>[] newListTable = createArray(newCapacity);
      threshold = (int) (newCapacity * LOAD_FACTOR);
      System.arraycopy(oldTable, 0, newListTable, 0, size);
      for (int i = 0; i < size; i++) {
        Entry<K, V> old = oldTable[i];
        int index = (old.hashCode & 0x7FFFFFFF) % newCapacity;
        Entry<K, V> e = old;
        old = old.next;
        e.next = newMapTable[index];
        newMapTable[index] = e;
      }
      mapTable = newMapTable;
      listTable = newListTable;
    }
  }

  private final V swapValue(final Entry<K, V> entry, final V value) {
    V old = entry.value;
    entry.value = value;
    return old;
  }

  @SuppressWarnings("unchecked")
  private Entry<K, V>[] createArray(final int length) {
    return new Entry[length];
  }

  private class ArrayMapIterator implements Iterator<Map.Entry<K, V>> {

    private int current = 0;

    private int last = -1;

    public boolean hasNext() {
      return current != size;
    }

    public Map.Entry<K, V> next() {
      try {
        Entry<K, V> n = listTable[current];
        last = current++;
        return n;
      } catch (IndexOutOfBoundsException e) {
        throw new NoSuchElementException();
      }
    }

    public void remove() {
      if (last == -1) {
        throw new IllegalStateException();
      }
      ArrayMap.this.remove(last);
      if (last < current) {
        current--;
      }
      last = -1;
    }
  }

  private static class Entry<K, V> implements Map.Entry<K, V>, Externalizable {

    private static final long serialVersionUID = 1L;

    transient int hashCode;

    transient K key;

    transient V value;

    transient Entry<K, V> next;

    /**
     * Constructor.
     * 
     * @param hashCode
     *            the hashCode
     * @param key
     *            the key
     * @param value
     *            the value
     * @param next
     *            the next
     */
    public Entry(final int hashCode, final K key, final V value,
        final Entry<K, V> next) {

      this.hashCode = hashCode;
      this.key = key;
      this.value = value;
      this.next = next;
    }

    public K getKey() {
      return key;
    }

    public V getValue() {
      return value;
    }

    public V setValue(final V value) {
      V oldValue = value;
      this.value = value;
      return oldValue;
    }

    /**
     * Clears contents.
     */
    public void clear() {
      key = null;
      value = null;
      next = null;
    }

    @Override
    public boolean equals(final Object o) {
      if (this == o) {
        return true;
      }
      Entry<?, ?> e = (Entry<?, ?>) o;
      return (key != null ? key.equals(e.key) : e.key == null)
          && (value != null ? value.equals(e.value) : e.value == null);
    }

    @Override
    public int hashCode() {
      return hashCode;
    }

    @Override
    public String toString() {
      return key + "=" + value;
    }

    public void writeExternal(final ObjectOutput s) throws IOException {
      s.writeInt(hashCode);
      s.writeObject(key);
      s.writeObject(value);
      s.writeObject(next);
    }

    @SuppressWarnings("unchecked")
    public void readExternal(final ObjectInput s) throws IOException,
        ClassNotFoundException {

      hashCode = s.readInt();
      key = (K) s.readObject();
      value = (V) s.readObject();
      next = (Entry) s.readObject();
    }
  }
}

   
    
    
    
    
    
  








Related examples in the same category

1.Set, HashSet and TreeSet
2.Things you can do with SetsThings you can do with Sets
3.Set operations: union, intersection, difference, symmetric difference, is subset, is superset
4.Set implementation that use == instead of equals()
5.Set that compares object by identity rather than equality
6.Set union and intersection
7.Set with values iterated in insertion order.
8.Putting your own type in a SetPutting your own type in a Set
9.Use setUse set
10.Another Set demo
11.Set subtractionSet subtraction
12.Working with HashSet and TreeSetWorking with HashSet and TreeSet
13.TreeSet DemoTreeSet Demo
14.Show the union and intersection of two sets
15.Demonstrate the Set interface
16.Array Set extends AbstractSetArray Set extends AbstractSet
17.Sync Test
18.Set Copy
19.Set and TreeSet
20.Tail
21.What you can do with a TreeSetWhat you can do with a TreeSet
22.Remove all elements from a set
23.Copy all the elements from set2 to set1 (set1 += set2), set1 becomes the union of set1 and set2
24.Remove all the elements in set1 from set2 (set1 -= set2), set1 becomes the asymmetric difference of set1 and set2
25.Get the intersection of set1 and set2, set1 becomes the intersection of set1 and set2
26.Extend AbstractSet to Create Simple Set
27.Int Set
28.One Item Set
29.Small sets whose elements are known to be unique by construction
30.List Set implements Set
31.Converts a char array to a Set
32.Converts a string to a Set
33.Implements the Set interface, backed by a ConcurrentHashMap instance
34.An IdentitySet that uses reference-equality instead of object-equality
35.An implementation of the java.util.Stack based on an ArrayList instead of a Vector, so it is not synchronized to protect against multi-threaded access.
36.A thin wrapper around a List transforming it into a modifiable Set.
37.A thread-safe Set that manages canonical objects
38.This program uses a set to print all unique words in System.in
39.Indexed Set
40.An ObjectToSet provides a java.util.Map from arbitrary objects to objects of class java.util.Set.
41.Sorted Multi Set
42.Fixed Size Sorted Set
43.Set operations
44.A NumberedSet is a generic container of Objects where each element is identified by an integer id.
45.Set which counts the number of times a values are added to it.
46.Set which counts the number of times a values are added to it and assigns them a unique positive index.
47.Indexed Set
48.Implements a Bloom filter. Which, as you may not know, is a space-efficient structure for storing a set.
49.Implementation of disjoint-set data structure
50.Call it an unordered list or a multiset, this collection is defined by oxymorons