/* * Part of the CCNx Java Library. * * Copyright (C) 2011 Palo Alto Research Center, Inc. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. * This library 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 * Lesser General Public License for more details. You should have received * a copy of the GNU Lesser General Public License along with this library; * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, * Fifth Floor, Boston, MA 02110-1301 USA. */ package org.ccnx.ccn.impl.support; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedList; import java.util.ListIterator; import java.util.TreeSet; /** * Add some missing features from the JDK 5 TreeSet. If * running on JDK 6, use them as they will be way more efficient. * This class is to provide JDK compatibility for the versioning * package and only implements the needed functionality. * * The user should call the *Compatible methods (floorCompatible, etc.) * instead of the Java 6 methods (e.g. floor). * * When used in a JDK 5 environment, the implementations of the * provided algorithms is going to be O(N), not O(log N). There is no * fast-fail detection for concurrent modifications. The descendingIterator * works fine for iteration and calling remove(), but if you mix in * other calls, like to add() while iterating, you will not see those * values. */ public class TreeSet6<E> extends TreeSet<E> { public TreeSet6() { initialize(); } public TreeSet6(Comparator<? super E> c) { super(c); initialize(); } /** * Returns the greatest element in this set less than or equal to the * given element, or null if there is no such element. * * Use this method, not floor(). */ @SuppressWarnings("unchecked") public E floorCompatible(E key) { if( null != floor ) try { return (E) floor.invoke(this, (Object) key); } catch (IllegalArgumentException e) { e.printStackTrace(); throw e; } catch (IllegalAccessException e) { e.printStackTrace(); throw new IllegalArgumentException(e.getMessage()); } catch (InvocationTargetException e) { e.printStackTrace(); throw new IllegalArgumentException(e.getMessage()); } return internalFloor(key); } /** * Returns the least element in this set greater than or equal to the * given element, or null if there is no such element. * * Use this method, not ceiling(). */ @SuppressWarnings("unchecked") public E ceilingCompatible(E key) { if( null != ceiling ) try { return (E) ceiling.invoke(this, (Object) key); } catch (IllegalArgumentException e) { e.printStackTrace(); throw e; } catch (IllegalAccessException e) { e.printStackTrace(); throw new IllegalArgumentException(e.getMessage()); } catch (InvocationTargetException e) { e.printStackTrace(); throw new IllegalArgumentException(e.getMessage()); } return internalCeiling(key); } /** * Returns the greatest element in this set strictly less than the * given element, or null if there is no such element. * * Use this method, not lower(). */ @SuppressWarnings("unchecked") public E lowerCompatible(E key) { if( null != lower ) try { return (E) lower.invoke(this, (Object) key); } catch (IllegalArgumentException e) { e.printStackTrace(); throw e; } catch (IllegalAccessException e) { e.printStackTrace(); throw new IllegalArgumentException(e.getMessage()); } catch (InvocationTargetException e) { e.printStackTrace(); throw new IllegalArgumentException(e.getMessage()); } return internalLower(key); } /** * Returns the least element in this set strictly greater than the * given element, or null if there is no such element. * * Use this method, not higher(). */ @SuppressWarnings("unchecked") public E higherCompatible(E key) { if( null != higher ) try { return (E) higher.invoke(this, (Object) key); } catch (IllegalArgumentException e) { e.printStackTrace(); throw e; } catch (IllegalAccessException e) { e.printStackTrace(); throw new IllegalArgumentException(e.getMessage()); } catch (InvocationTargetException e) { e.printStackTrace(); throw new IllegalArgumentException(e.getMessage()); } return internalHigher(key); } /** * Returns an iterator over the elements in this set in descending order. * @return */ @SuppressWarnings("unchecked") public Iterator<E> descendingIteratorCompatible() { if( null != higher ) try { return (Iterator<E>) descendingIterator.invoke(this); } catch (IllegalArgumentException e) { e.printStackTrace(); throw e; } catch (IllegalAccessException e) { e.printStackTrace(); throw new IllegalArgumentException(e.getMessage()); } catch (InvocationTargetException e) { e.printStackTrace(); throw new IllegalArgumentException(e.getMessage()); } return internalDescendingIterator(); } // ============================================= private static final long serialVersionUID = 7840825335033077895L; // These are transient because they should not be considered part of the TreeSet's // serializable state private transient Method floor = null; private transient Method ceiling = null; private transient Method lower = null; private transient Method higher = null; private transient Method descendingIterator = null; /** * Our own wrapper for getMethod that returns null if the method is not found. * @param c class to search for method * @param name method name * @param parameterTypes * @return the method or null if not found */ protected Method getMethod(Class<?> c, String name, Class<?>... parameterTypes) { Method m = null; try { m = c.getMethod(name, parameterTypes); } catch (NoSuchMethodException nsme) { // ignore this, we'll just return null } return m; } private Iterator<E> internalDescendingIterator() { return new DescendingIterator<E>(); } private void initialize() { try { Class<?>[] parameterTypes = new Class[] { Object.class }; Class<?> c = this.getClass(); Class<?> cc = c.getSuperclass(); try { floor = cc.getMethod("floor", parameterTypes); } catch(NoSuchMethodException nsme) {} try { ceiling = cc.getMethod("ceiling", parameterTypes); } catch(NoSuchMethodException nsme) {} try { lower = cc.getMethod("lower", parameterTypes); } catch(NoSuchMethodException nsme) {} try { higher = cc.getMethod("higher", parameterTypes); } catch(NoSuchMethodException nsme) {} try { descendingIterator = cc.getMethod("descendingIterator"); } catch(NoSuchMethodException nsme) {} } catch (Exception e) { e.printStackTrace(); } } /** * Returns the greatest element in this set less than or equal to the * given element, or null if there is no such element. */ @SuppressWarnings("unchecked") protected E internalFloor(E key) { Comparator<? super E> comparator = this.comparator(); Comparable<? super E> comparable = null; if( key instanceof Comparable<?>) { comparable = (Comparable<? super E>) key; } E rtn = null; Iterator<E> iter = iterator(); while( iter.hasNext() ) { E test = iter.next(); // An exact match, return the test value if( mycompare(comparator, comparable, key, test) == 0 ) return test; // key is before test, so we have run past the place // where the floor could be. Return our best result so far. if( mycompare(comparator, comparable, key, test) < 0 ) return rtn; // else test < key, so keep looking rtn = test; } return rtn; } /** * Returns the least element in this set greater than or equal to the * given element, or null if there is no such element. */ @SuppressWarnings("unchecked") protected E internalCeiling(E key) { Comparator<? super E> comparator = this.comparator(); Comparable<? super E> comparable = null; if( key instanceof Comparable<?>) { comparable = (Comparable<? super E>) key; } E rtn = null; Iterator<E> iter = iterator(); while( iter.hasNext() ) { E test = iter.next(); // An exact match, return the test value if( mycompare(comparator, comparable, key, test) == 0 ) return test; // key is before test, so we have come to the // first element in the set greater than key // without equality, so return this. if( mycompare(comparator, comparable, key, test) < 0 ) return test; // else test < key, so keep looking rtn = test; } return rtn; } /** * Returns the least element in this set strictly greater than the * given element, or null if there is no such element. */ @SuppressWarnings("unchecked") protected E internalHigher(E key) { Comparator<? super E> comparator = this.comparator(); Comparable<? super E> comparable = null; if( key instanceof Comparable<?>) { comparable = (Comparable<? super E>) key; } E rtn = null; Iterator<E> iter = iterator(); while( iter.hasNext() ) { E test = iter.next(); // key is before test, so we have come to the // first element in the set greater than key // without equality, so return this. if( mycompare(comparator, comparable, key, test) < 0 ) return test; // else test <= key, so keep looking rtn = test; } return rtn; } /** * Returns the greatest element in this set strictly less than the * given element, or null if there is no such element. */ @SuppressWarnings("unchecked") protected E internalLower(E key) { Comparator<? super E> comparator = this.comparator(); Comparable<? super E> comparable = null; if( key instanceof Comparable<?>) { comparable = (Comparable<? super E>) key; } E rtn = null; Iterator<E> iter = iterator(); while( iter.hasNext() ) { E test = iter.next(); // An exact match, return the last test value visited if( mycompare(comparator, comparable, key, test) == 0 ) return rtn; // key is before test, so we have run past the place // where the floor could be. Return our best result so far. if( mycompare(comparator, comparable, key, test) < 0 ) return rtn; // else test < key, so keep looking rtn = test; } return rtn; } /** * if comp not null, use comp, else use comparable if not null, else * throw a ClassCast exception * @param comparator the Comparator to use * @param comparable the casting to (Comparable) from a * @param a * @param b * @return -1 if a<b, 0 a==0, +1 a>b */ protected int mycompare(Comparator<? super E> comparator, Comparable<? super E> comparable, E a, E b) throws ClassCastException { if( null != comparator ) return(comparator.compare(a,b)); if( null != comparable ) return(comparable.compareTo(b)); throw new ClassCastException("not comparable"); } // ================================================ protected class DescendingIterator<T> implements Iterator<T> { private final LinkedList<T> _list; private ListIterator<T> _listIterator; private T _lastReturnedValue = null; @SuppressWarnings("unchecked") public DescendingIterator() { _list = new LinkedList<T>((Collection<? extends T>) TreeSet6.this); _listIterator = _list.listIterator(); // now move the iterator to the end while(_listIterator.hasNext()) _listIterator.next(); } public boolean hasNext() { return _listIterator.hasPrevious(); } public T next() { _lastReturnedValue = _listIterator.previous(); return _lastReturnedValue; } public void remove() { if( null == _lastReturnedValue ) throw new IllegalStateException("Remove has already been called or no value has been returned"); _listIterator.remove(); TreeSet6.this.remove(_lastReturnedValue); _lastReturnedValue = null; } } }