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

soot.util.HashChain Maven / Gradle / Ivy

package soot.util;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 1999 Patrice Pominville
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 2.1 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Reference implementation of the Chain interface, using a HashMap as the underlying structure.
 */
public class HashChain extends AbstractCollection implements Chain {
  protected Map> map = new ConcurrentHashMap>();
  protected E firstItem;
  protected E lastItem;
  protected int stateCount = 0;

  @SuppressWarnings("rawtypes")
  protected static final Iterator emptyIterator = new Iterator() {

    @Override
    public boolean hasNext() {
      return false;
    }

    @Override
    public Object next() {
      return null;
    }

    @Override
    public void remove() {
      // do nothing
    }

  };

  /** Erases the contents of the current HashChain. */
  @Override
  public void clear() {
    stateCount++;
    firstItem = lastItem = null;
    map.clear();
  }

  @Override
  public void swapWith(E out, E in) {
    insertBefore(in, out);
    remove(out);
  }

  /** Adds the given object to this HashChain. */
  @Override
  public boolean add(E item) {
    addLast(item);
    return true;
  }

  /**
   * Gets all elements in the chain. There is no guarantee on sorting.
   *
   * @return All elements in the chain in an unsorted collection
   */
  @Override
  public Collection getElementsUnsorted() {
    return map.keySet();
  }

  /**
   * Returns an unbacked list containing the contents of the given Chain.
   *
   * @deprecated you can use new ArrayList(c) instead
   */
  @Deprecated
  public static  List toList(Chain c) {
    return new ArrayList(c);
  }

  /** Constructs an empty HashChain. */
  public HashChain() {
    firstItem = lastItem = null;
  }

  /** Constructs a HashChain filled with the contents of the src Chain. */
  public HashChain(Chain src) {
    this();
    addAll(src);
  }

  @Override
  public boolean follows(E someObject, E someReferenceObject) {
    Iterator it = iterator(someObject);
    while (it.hasNext()) {
      if (it.next() == someReferenceObject) {
        return false;
      }
    }
    return true;
  }

  @Override
  public boolean contains(Object o) {
    return map.containsKey(o);
  }

  @Override
  public boolean containsAll(Collection c) {
    Iterator it = c.iterator();
    while (it.hasNext()) {
      if (!(map.containsKey(it.next()))) {
        return false;
      }
    }

    return true;
  }

  @Override
  public void insertAfter(E toInsert, E point) {
    if (toInsert == null) {
      throw new RuntimeException("Bad idea! You tried to insert " + " a null object into a Chain!");
    }

    if (map.containsKey(toInsert)) {
      throw new RuntimeException("Chain already contains object.");
    }

    Link temp = map.get(point);
    if (temp == null) {
      throw new RuntimeException("Insertion point not found in chain!");
    }

    stateCount++;

    Link newLink = temp.insertAfter(toInsert);
    map.put(toInsert, newLink);
  }

  public void insertAfter(Collection toInsert, E point) {
    // if the list is null, treat it as an empty list
    if (toInsert == null) {
      throw new RuntimeException("Warning! You tried to insert " + "a null list into a Chain!");
    }

    E previousPoint = point;
    for (E o : toInsert) {
      insertAfter(o, previousPoint);
      previousPoint = o;
    }
  }

  @Override
  public void insertAfter(List toInsert, E point) {
    insertAfter((Collection) toInsert, point);
  }

  @Override
  public void insertAfter(Chain toInsert, E point) {
    insertAfter((Collection) toInsert, point);
  }

  @Override
  public void insertBefore(E toInsert, E point) {
    if (toInsert == null) {
      throw new RuntimeException("Bad idea! You tried to insert " + "a null object into a Chain!");
    }

    if (map.containsKey(toInsert)) {
      throw new RuntimeException("Chain already contains object.");
    }

    Link temp = map.get(point);
    if (temp == null) {
      throw new RuntimeException("Insertion point not found in chain!");
    }
    stateCount++;

    Link newLink = temp.insertBefore(toInsert);
    map.put(toInsert, newLink);
  }

  public void insertBefore(Collection toInsert, E point) {
    // if the list is null, treat it as an empty list
    if (toInsert == null) {
      throw new RuntimeException("Warning! You tried to insert a null list into a Chain!");
    }

    for (E o : toInsert) {
      insertBefore(o, point);
    }
  }

  @Override
  public void insertBefore(List toInsert, E point) {
    insertBefore((Collection) toInsert, point);
  }

  @Override
  public void insertBefore(Chain toInsert, E point) {
    insertBefore((Collection) toInsert, point);
  }

  public static  HashChain listToHashChain(List list) {
    HashChain c = new HashChain();
    Iterator it = list.iterator();
    while (it.hasNext()) {
      c.addLast(it.next());
    }
    return c;
  }

  @Override
  public boolean remove(Object item) {
    if (item == null) {
      throw new RuntimeException("Bad idea! You tried to remove " + " a null object from a Chain!");
    }

    stateCount++;
    /*
     * 4th April 2005 Nomair A Naeem map.get(obj) can return null only return true if this is non null else return false
     */
    Link link = map.get(item);
    if (link != null) {
      link.unlinkSelf();
      map.remove(item);
      return true;
    }
    return false;
  }

  @Override
  public void addFirst(E item) {
    if (item == null) {
      throw new RuntimeException("Bad idea!  You tried to insert " + "a null object into a Chain!");
    }

    stateCount++;
    Link newLink, temp;

    if (map.containsKey(item)) {
      throw new RuntimeException("Chain already contains object.");
    }

    if (firstItem != null) {
      temp = map.get(firstItem);
      newLink = temp.insertBefore(item);
    } else {
      newLink = new Link(item);
      firstItem = lastItem = item;
    }
    map.put(item, newLink);
  }

  @Override
  public void addLast(E item) {
    if (item == null) {
      throw new RuntimeException("Bad idea! You tried to insert " + " a null object into a Chain!");
    }

    stateCount++;
    Link newLink, temp;
    if (map.containsKey(item)) {
      throw new RuntimeException("Chain already contains object: " + item);
    }

    if (lastItem != null) {
      temp = map.get(lastItem);
      newLink = temp.insertAfter(item);
    } else {
      newLink = new Link(item);
      firstItem = lastItem = item;
    }
    map.put(item, newLink);
  }

  @Override
  public void removeFirst() {
    stateCount++;
    Object item = firstItem;
    map.get(firstItem).unlinkSelf();
    map.remove(item);
  }

  @Override
  public void removeLast() {
    stateCount++;
    Object item = lastItem;
    map.get(lastItem).unlinkSelf();
    map.remove(item);
  }

  @Override
  public E getFirst() {
    if (firstItem == null) {
      throw new NoSuchElementException();
    }
    return firstItem;
  }

  @Override
  public E getLast() {
    if (lastItem == null) {
      throw new NoSuchElementException();
    }
    return lastItem;
  }

  @Override
  public E getSuccOf(E point) throws NoSuchElementException {
    Link link = map.get(point);
    try {
      link = link.getNext();
    } catch (NullPointerException e) {
      throw new NoSuchElementException();
    }
    if (link == null) {
      return null;
    }

    return link.getItem();
  }

  @Override
  public E getPredOf(E point) throws NoSuchElementException {
    Link link = map.get(point);
    if (point == null) {
      throw new RuntimeException("trying to hash null value.");
    }

    try {
      link = link.getPrevious();
    } catch (NullPointerException e) {
      throw new NoSuchElementException();
    }

    if (link == null) {
      return null;
    } else {
      return link.getItem();
    }
  }

  @Override
  public Iterator snapshotIterator() {
    return (new ArrayList(this)).iterator();
  }

  public Iterator snapshotIterator(E item) {
    List l = new ArrayList(map.size());

    Iterator it = new LinkIterator(item);
    while (it.hasNext()) {
      l.add(it.next());
    }

    return l.iterator();
  }

  @Override
  @SuppressWarnings("unchecked")
  public Iterator iterator() {
    if (firstItem == null || isEmpty()) {
      return (Iterator) emptyIterator;
    }
    return new LinkIterator(firstItem);
  }

  @Override
  @SuppressWarnings("unchecked")
  public Iterator iterator(E item) {
    if (firstItem == null || isEmpty()) {
      return (Iterator) emptyIterator;
    }
    return new LinkIterator(item);
  }

  /**
   * 

* Returns an iterator ranging from head to tail, inclusive. *

* *

* If tail is the element immediately preceding head in this HashChain, the returned * iterator will iterate 0 times (a special case to allow the specification of an empty range of elements). Otherwise if * tail is not one of the elements following head, the returned iterator will iterate past the * end of the HashChain, provoking a {@link NoSuchElementException}. *

* * @throws NoSuchElementException * if head is not an element of the chain. */ @Override @SuppressWarnings("unchecked") public Iterator iterator(E head, E tail) { if (firstItem == null || isEmpty()) { return (Iterator) emptyIterator; } if (head != null && this.getPredOf(head) == tail) { return (Iterator) emptyIterator; } return new LinkIterator(head, tail); } @Override public int size() { return map.size(); } /** Returns a textual representation of the contents of this Chain. */ @Override public String toString() { StringBuilder strBuf = new StringBuilder(); Iterator it = iterator(); boolean b = false; strBuf.append("["); while (it.hasNext()) { if (!b) { b = true; } else { strBuf.append(", "); } strBuf.append(it.next().toString()); } strBuf.append("]"); return strBuf.toString(); } @SuppressWarnings("serial") protected class Link implements Serializable { private Link nextLink; private Link previousLink; private X item; public Link(X item) { this.item = item; nextLink = previousLink = null; } public Link getNext() { return nextLink; } public Link getPrevious() { return previousLink; } public void setNext(Link link) { this.nextLink = link; } public void setPrevious(Link link) { this.previousLink = link; } public void unlinkSelf() { bind(previousLink, nextLink); } public Link insertAfter(X item) { Link newLink = new Link(item); bind(newLink, nextLink); bind(this, newLink); return newLink; } public Link insertBefore(X item) { Link newLink = new Link(item); bind(previousLink, newLink); bind(newLink, this); return newLink; } private void bind(Link a, Link b) { if (a == null) { firstItem = (b == null) ? null : b.item; } else { a.nextLink = b; } if (b == null) { lastItem = (a == null) ? null : a.item; } else { b.previousLink = a; } } public X getItem() { return item; } @Override public String toString() { if (item != null) { return item.toString(); } else { return "Link item is null" + super.toString(); } } } protected class LinkIterator implements Iterator { private Link currentLink; boolean state; // only when this is true can remove() be called // (in accordance w/ iterator semantics) private X destination; private int iteratorStateCount; public LinkIterator(X item) { Link nextLink = map.get(item); if (nextLink == null && item != null) { throw new NoSuchElementException( "HashChain.LinkIterator(obj) with obj that is not in the chain: " + item.toString()); } currentLink = new Link(null); currentLink.setNext(nextLink); state = false; destination = null; iteratorStateCount = stateCount; } public LinkIterator(X from, X to) { this(from); destination = to; } @Override public boolean hasNext() { if (stateCount != iteratorStateCount) { throw new ConcurrentModificationException(); } if (destination == null) { return (currentLink.getNext() != null); } else { // Ignore whether (currentLink.getNext() == null), so // next() will produce a NoSuchElementException if // destination is not in the chain. return (destination != currentLink.getItem()); } } @Override public E next() throws NoSuchElementException { if (stateCount != iteratorStateCount) { throw new ConcurrentModificationException(); } Link temp = currentLink.getNext(); if (temp == null) { String exceptionMsg; if (destination != null && destination != currentLink.getItem()) { exceptionMsg = "HashChain.LinkIterator.next() reached end of chain without reaching specified tail unit"; } else { exceptionMsg = "HashChain.LinkIterator.next() called past the end of the Chain"; } throw new NoSuchElementException(exceptionMsg); } currentLink = temp; state = true; return currentLink.getItem(); } @Override public void remove() throws IllegalStateException { if (stateCount != iteratorStateCount) { throw new ConcurrentModificationException(); } stateCount++; iteratorStateCount++; if (!state) { throw new IllegalStateException(); } else { currentLink.unlinkSelf(); map.remove(currentLink.getItem()); state = false; } } @Override public String toString() { if (currentLink == null) { return "Current object under iterator is null" + super.toString(); } else { return currentLink.toString(); } } } /** Returns the number of times this chain has been modified. */ @Override public long getModificationCount() { return stateCount; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy