From 6f6c6cda3445f8c3178ca4988bada82bd09e8c19 Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Sun, 26 Jan 2014 15:01:12 +0000 Subject: [PATCH] As Jdk 1.5 doesn't provide NavigableMap/Set classes of JDK 1.6, we temporarily use the open jdk classes instead, until POI has switched to JDK 1.6 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1561500 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/util/java7_util/AbstractMap7.java | 828 ++++++ .../poi/util/java7_util/AbstractSet7.java | 190 ++ .../poi/util/java7_util/NavigableMap7.java | 429 +++ .../poi/util/java7_util/NavigableSet7.java | 324 +++ .../apache/poi/util/java7_util/TreeMap7.java | 2458 +++++++++++++++++ .../apache/poi/util/java7_util/TreeSet7.java | 554 ++++ .../xssf/usermodel/helpers/ColumnHelper.java | 4 +- 7 files changed, 4785 insertions(+), 2 deletions(-) create mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/AbstractMap7.java create mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/AbstractSet7.java create mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/NavigableMap7.java create mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/NavigableSet7.java create mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/TreeMap7.java create mode 100644 src/ooxml/java/org/apache/poi/util/java7_util/TreeSet7.java diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/AbstractMap7.java b/src/ooxml/java/org/apache/poi/util/java7_util/AbstractMap7.java new file mode 100644 index 000000000..6e65da7f2 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/java7_util/AbstractMap7.java @@ -0,0 +1,828 @@ +/* + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.apache.poi.util.java7_util; + +import java.util.AbstractCollection; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * This class provides a skeletal implementation of the Map + * interface, to minimize the effort required to implement this interface. + * + *

To implement an unmodifiable map, the programmer needs only to extend this + * class and provide an implementation for the entrySet method, which + * returns a set-view of the map's mappings. Typically, the returned set + * will, in turn, be implemented atop AbstractSet. This set should + * not support the add or remove methods, and its iterator + * should not support the remove method. + * + *

To implement a modifiable map, the programmer must additionally override + * this class's put method (which otherwise throws an + * UnsupportedOperationException), and the iterator returned by + * entrySet().iterator() must additionally implement its + * remove method. + * + *

The programmer should generally provide a void (no argument) and map + * constructor, as per the recommendation in the Map interface + * specification. + * + *

The documentation for each non-abstract method in this class describes its + * implementation in detail. Each of these methods may be overridden if the + * map being implemented admits a more efficient implementation. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @param the type of keys maintained by this map + * @param the type of mapped values + * + * @author Josh Bloch + * @author Neal Gafter + * @see Map + * @see Collection + * @since 1.2 + */ + +public abstract class AbstractMap7 implements Map { + /** + * Sole constructor. (For invocation by subclass constructors, typically + * implicit.) + */ + protected AbstractMap7() { + } + + // Query Operations + + /** + * {@inheritDoc} + * + *

This implementation returns entrySet().size(). + */ + public int size() { + return entrySet().size(); + } + + /** + * {@inheritDoc} + * + *

This implementation returns size() == 0. + */ + public boolean isEmpty() { + return size() == 0; + } + + /** + * {@inheritDoc} + * + *

This implementation iterates over entrySet() searching + * for an entry with the specified value. If such an entry is found, + * true is returned. If the iteration terminates without + * finding such an entry, false is returned. Note that this + * implementation requires linear time in the size of the map. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public boolean containsValue(Object value) { + Iterator> i = entrySet().iterator(); + if (value==null) { + while (i.hasNext()) { + Entry e = i.next(); + if (e.getValue()==null) + return true; + } + } else { + while (i.hasNext()) { + Entry e = i.next(); + if (value.equals(e.getValue())) + return true; + } + } + return false; + } + + /** + * {@inheritDoc} + * + *

This implementation iterates over entrySet() searching + * for an entry with the specified key. If such an entry is found, + * true is returned. If the iteration terminates without + * finding such an entry, false is returned. Note that this + * implementation requires linear time in the size of the map; many + * implementations will override this method. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public boolean containsKey(Object key) { + Iterator> i = entrySet().iterator(); + if (key==null) { + while (i.hasNext()) { + Entry e = i.next(); + if (e.getKey()==null) + return true; + } + } else { + while (i.hasNext()) { + Entry e = i.next(); + if (key.equals(e.getKey())) + return true; + } + } + return false; + } + + /** + * {@inheritDoc} + * + *

This implementation iterates over entrySet() searching + * for an entry with the specified key. If such an entry is found, + * the entry's value is returned. If the iteration terminates without + * finding such an entry, null is returned. Note that this + * implementation requires linear time in the size of the map; many + * implementations will override this method. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public V get(Object key) { + Iterator> i = entrySet().iterator(); + if (key==null) { + while (i.hasNext()) { + Entry e = i.next(); + if (e.getKey()==null) + return e.getValue(); + } + } else { + while (i.hasNext()) { + Entry e = i.next(); + if (key.equals(e.getKey())) + return e.getValue(); + } + } + return null; + } + + + // Modification Operations + + /** + * {@inheritDoc} + * + *

This implementation always throws an + * UnsupportedOperationException. + * + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public V put(K key, V value) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + * + *

This implementation iterates over entrySet() searching for an + * entry with the specified key. If such an entry is found, its value is + * obtained with its getValue operation, the entry is removed + * from the collection (and the backing map) with the iterator's + * remove operation, and the saved value is returned. If the + * iteration terminates without finding such an entry, null is + * returned. Note that this implementation requires linear time in the + * size of the map; many implementations will override this method. + * + *

Note that this implementation throws an + * UnsupportedOperationException if the entrySet + * iterator does not support the remove method and this map + * contains a mapping for the specified key. + * + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + public V remove(Object key) { + Iterator> i = entrySet().iterator(); + Entry correctEntry = null; + if (key==null) { + while (correctEntry==null && i.hasNext()) { + Entry e = i.next(); + if (e.getKey()==null) + correctEntry = e; + } + } else { + while (correctEntry==null && i.hasNext()) { + Entry e = i.next(); + if (key.equals(e.getKey())) + correctEntry = e; + } + } + + V oldValue = null; + if (correctEntry !=null) { + oldValue = correctEntry.getValue(); + i.remove(); + } + return oldValue; + } + + + // Bulk Operations + + /** + * {@inheritDoc} + * + *

This implementation iterates over the specified map's + * entrySet() collection, and calls this map's put + * operation once for each entry returned by the iteration. + * + *

Note that this implementation throws an + * UnsupportedOperationException if this map does not support + * the put operation and the specified map is nonempty. + * + * @throws UnsupportedOperationException {@inheritDoc} + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + public void putAll(Map m) { + for (Map.Entry e : m.entrySet()) + put(e.getKey(), e.getValue()); + } + + /** + * {@inheritDoc} + * + *

This implementation calls entrySet().clear(). + * + *

Note that this implementation throws an + * UnsupportedOperationException if the entrySet + * does not support the clear operation. + * + * @throws UnsupportedOperationException {@inheritDoc} + */ + public void clear() { + entrySet().clear(); + } + + + // Views + + /** + * Each of these fields are initialized to contain an instance of the + * appropriate view the first time this view is requested. The views are + * stateless, so there's no reason to create more than one of each. + */ + transient volatile Set keySet = null; + transient volatile Collection values = null; + + /** + * {@inheritDoc} + * + *

This implementation returns a set that subclasses {@link AbstractSet}. + * The subclass's iterator method returns a "wrapper object" over this + * map's entrySet() iterator. The size method + * delegates to this map's size method and the + * contains method delegates to this map's + * containsKey method. + * + *

The set is created the first time this method is called, + * and returned in response to all subsequent calls. No synchronization + * is performed, so there is a slight chance that multiple calls to this + * method will not all return the same set. + */ + public Set keySet() { + if (keySet == null) { + keySet = new AbstractSet() { + public Iterator iterator() { + return new Iterator() { + private Iterator> i = entrySet().iterator(); + + public boolean hasNext() { + return i.hasNext(); + } + + public K next() { + return i.next().getKey(); + } + + public void remove() { + i.remove(); + } + }; + } + + public int size() { + return AbstractMap7.this.size(); + } + + public boolean isEmpty() { + return AbstractMap7.this.isEmpty(); + } + + public void clear() { + AbstractMap7.this.clear(); + } + + public boolean contains(Object k) { + return AbstractMap7.this.containsKey(k); + } + }; + } + return keySet; + } + + /** + * {@inheritDoc} + * + *

This implementation returns a collection that subclasses {@link + * AbstractCollection}. The subclass's iterator method returns a + * "wrapper object" over this map's entrySet() iterator. + * The size method delegates to this map's size + * method and the contains method delegates to this map's + * containsValue method. + * + *

The collection is created the first time this method is called, and + * returned in response to all subsequent calls. No synchronization is + * performed, so there is a slight chance that multiple calls to this + * method will not all return the same collection. + */ + public Collection values() { + if (values == null) { + values = new AbstractCollection() { + public Iterator iterator() { + return new Iterator() { + private Iterator> i = entrySet().iterator(); + + public boolean hasNext() { + return i.hasNext(); + } + + public V next() { + return i.next().getValue(); + } + + public void remove() { + i.remove(); + } + }; + } + + public int size() { + return AbstractMap7.this.size(); + } + + public boolean isEmpty() { + return AbstractMap7.this.isEmpty(); + } + + public void clear() { + AbstractMap7.this.clear(); + } + + public boolean contains(Object v) { + return AbstractMap7.this.containsValue(v); + } + }; + } + return values; + } + + public abstract Set> entrySet(); + + + // Comparison and hashing + + /** + * Compares the specified object with this map for equality. Returns + * true if the given object is also a map and the two maps + * represent the same mappings. More formally, two maps m1 and + * m2 represent the same mappings if + * m1.entrySet().equals(m2.entrySet()). This ensures that the + * equals method works properly across different implementations + * of the Map interface. + * + *

This implementation first checks if the specified object is this map; + * if so it returns true. Then, it checks if the specified + * object is a map whose size is identical to the size of this map; if + * not, it returns false. If so, it iterates over this map's + * entrySet collection, and checks that the specified map + * contains each mapping that this map contains. If the specified map + * fails to contain such a mapping, false is returned. If the + * iteration completes, true is returned. + * + * @param o object to be compared for equality with this map + * @return true if the specified object is equal to this map + */ + public boolean equals(Object o) { + if (o == this) + return true; + + if (!(o instanceof Map)) + return false; + Map m = (Map) o; + if (m.size() != size()) + return false; + + try { + Iterator> i = entrySet().iterator(); + while (i.hasNext()) { + Entry e = i.next(); + K key = e.getKey(); + V value = e.getValue(); + if (value == null) { + if (!(m.get(key)==null && m.containsKey(key))) + return false; + } else { + if (!value.equals(m.get(key))) + return false; + } + } + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + + return true; + } + + /** + * Returns the hash code value for this map. The hash code of a map is + * defined to be the sum of the hash codes of each entry in the map's + * entrySet() view. This ensures that m1.equals(m2) + * implies that m1.hashCode()==m2.hashCode() for any two maps + * m1 and m2, as required by the general contract of + * {@link Object#hashCode}. + * + *

This implementation iterates over entrySet(), calling + * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the + * set, and adding up the results. + * + * @return the hash code value for this map + * @see Map.Entry#hashCode() + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + public int hashCode() { + int h = 0; + Iterator> i = entrySet().iterator(); + while (i.hasNext()) + h += i.next().hashCode(); + return h; + } + + /** + * Returns a string representation of this map. The string representation + * consists of a list of key-value mappings in the order returned by the + * map's entrySet view's iterator, enclosed in braces + * ("{}"). Adjacent mappings are separated by the characters + * ", " (comma and space). Each key-value mapping is rendered as + * the key followed by an equals sign ("=") followed by the + * associated value. Keys and values are converted to strings as by + * {@link String#valueOf(Object)}. + * + * @return a string representation of this map + */ + public String toString() { + Iterator> i = entrySet().iterator(); + if (! i.hasNext()) + return "{}"; + + StringBuilder sb = new StringBuilder(); + sb.append('{'); + for (;;) { + Entry e = i.next(); + K key = e.getKey(); + V value = e.getValue(); + sb.append(key == this ? "(this Map)" : key); + sb.append('='); + sb.append(value == this ? "(this Map)" : value); + if (! i.hasNext()) + return sb.append('}').toString(); + sb.append(',').append(' '); + } + } + + /** + * Returns a shallow copy of this AbstractMap7 instance: the keys + * and values themselves are not cloned. + * + * @return a shallow copy of this map + */ + protected Object clone() throws CloneNotSupportedException { + AbstractMap7 result = (AbstractMap7)super.clone(); + result.keySet = null; + result.values = null; + return result; + } + + /** + * Utility method for SimpleEntry and SimpleImmutableEntry. + * Test for equality, checking for nulls. + */ + private static boolean eq(Object o1, Object o2) { + return o1 == null ? o2 == null : o1.equals(o2); + } + + // Implementation Note: SimpleEntry and SimpleImmutableEntry + // are distinct unrelated classes, even though they share + // some code. Since you can't add or subtract final-ness + // of a field in a subclass, they can't share representations, + // and the amount of duplicated code is too small to warrant + // exposing a common abstract class. + + + /** + * An Entry maintaining a key and a value. The value may be + * changed using the setValue method. This class + * facilitates the process of building custom map + * implementations. For example, it may be convenient to return + * arrays of SimpleEntry instances in method + * Map.entrySet().toArray. + * + * @since 1.6 + */ + public static class SimpleEntry + implements Entry, java.io.Serializable + { + private static final long serialVersionUID = -8499721149061103585L; + + private final K key; + private V value; + + /** + * Creates an entry representing a mapping from the specified + * key to the specified value. + * + * @param key the key represented by this entry + * @param value the value represented by this entry + */ + public SimpleEntry(K key, V value) { + this.key = key; + this.value = value; + } + + /** + * Creates an entry representing the same mapping as the + * specified entry. + * + * @param entry the entry to copy + */ + public SimpleEntry(Entry entry) { + this.key = entry.getKey(); + this.value = entry.getValue(); + } + + /** + * Returns the key corresponding to this entry. + * + * @return the key corresponding to this entry + */ + public K getKey() { + return key; + } + + /** + * Returns the value corresponding to this entry. + * + * @return the value corresponding to this entry + */ + public V getValue() { + return value; + } + + /** + * Replaces the value corresponding to this entry with the specified + * value. + * + * @param value new value to be stored in this entry + * @return the old value corresponding to the entry + */ + public V setValue(V value) { + V oldValue = this.value; + this.value = value; + return oldValue; + } + + /** + * Compares the specified object with this entry for equality. + * Returns {@code true} if the given object is also a map entry and + * the two entries represent the same mapping. More formally, two + * entries {@code e1} and {@code e2} represent the same mapping + * if

+         *   (e1.getKey()==null ?
+         *    e2.getKey()==null :
+         *    e1.getKey().equals(e2.getKey()))
+         *   &&
+         *   (e1.getValue()==null ?
+         *    e2.getValue()==null :
+         *    e1.getValue().equals(e2.getValue()))
+ * This ensures that the {@code equals} method works properly across + * different implementations of the {@code Map.Entry} interface. + * + * @param o object to be compared for equality with this map entry + * @return {@code true} if the specified object is equal to this map + * entry + * @see #hashCode + */ + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + return eq(key, e.getKey()) && eq(value, e.getValue()); + } + + /** + * Returns the hash code value for this map entry. The hash code + * of a map entry {@code e} is defined to be:
+         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *   (e.getValue()==null ? 0 : e.getValue().hashCode())
+ * This ensures that {@code e1.equals(e2)} implies that + * {@code e1.hashCode()==e2.hashCode()} for any two Entries + * {@code e1} and {@code e2}, as required by the general + * contract of {@link Object#hashCode}. + * + * @return the hash code value for this map entry + * @see #equals + */ + public int hashCode() { + return (key == null ? 0 : key.hashCode()) ^ + (value == null ? 0 : value.hashCode()); + } + + /** + * Returns a String representation of this map entry. This + * implementation returns the string representation of this + * entry's key followed by the equals character ("=") + * followed by the string representation of this entry's value. + * + * @return a String representation of this map entry + */ + public String toString() { + return key + "=" + value; + } + + } + + /** + * An Entry maintaining an immutable key and value. This class + * does not support method setValue. This class may be + * convenient in methods that return thread-safe snapshots of + * key-value mappings. + * + * @since 1.6 + */ + public static class SimpleImmutableEntry + implements Entry, java.io.Serializable + { + private static final long serialVersionUID = 7138329143949025153L; + + private final K key; + private final V value; + + /** + * Creates an entry representing a mapping from the specified + * key to the specified value. + * + * @param key the key represented by this entry + * @param value the value represented by this entry + */ + public SimpleImmutableEntry(K key, V value) { + this.key = key; + this.value = value; + } + + /** + * Creates an entry representing the same mapping as the + * specified entry. + * + * @param entry the entry to copy + */ + public SimpleImmutableEntry(Entry entry) { + this.key = entry.getKey(); + this.value = entry.getValue(); + } + + /** + * Returns the key corresponding to this entry. + * + * @return the key corresponding to this entry + */ + public K getKey() { + return key; + } + + /** + * Returns the value corresponding to this entry. + * + * @return the value corresponding to this entry + */ + public V getValue() { + return value; + } + + /** + * Replaces the value corresponding to this entry with the specified + * value (optional operation). This implementation simply throws + * UnsupportedOperationException, as this class implements + * an immutable map entry. + * + * @param value new value to be stored in this entry + * @return (Does not return) + * @throws UnsupportedOperationException always + */ + public V setValue(V value) { + throw new UnsupportedOperationException(); + } + + /** + * Compares the specified object with this entry for equality. + * Returns {@code true} if the given object is also a map entry and + * the two entries represent the same mapping. More formally, two + * entries {@code e1} and {@code e2} represent the same mapping + * if
+         *   (e1.getKey()==null ?
+         *    e2.getKey()==null :
+         *    e1.getKey().equals(e2.getKey()))
+         *   &&
+         *   (e1.getValue()==null ?
+         *    e2.getValue()==null :
+         *    e1.getValue().equals(e2.getValue()))
+ * This ensures that the {@code equals} method works properly across + * different implementations of the {@code Map.Entry} interface. + * + * @param o object to be compared for equality with this map entry + * @return {@code true} if the specified object is equal to this map + * entry + * @see #hashCode + */ + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + return eq(key, e.getKey()) && eq(value, e.getValue()); + } + + /** + * Returns the hash code value for this map entry. The hash code + * of a map entry {@code e} is defined to be:
+         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *   (e.getValue()==null ? 0 : e.getValue().hashCode())
+ * This ensures that {@code e1.equals(e2)} implies that + * {@code e1.hashCode()==e2.hashCode()} for any two Entries + * {@code e1} and {@code e2}, as required by the general + * contract of {@link Object#hashCode}. + * + * @return the hash code value for this map entry + * @see #equals + */ + public int hashCode() { + return (key == null ? 0 : key.hashCode()) ^ + (value == null ? 0 : value.hashCode()); + } + + /** + * Returns a String representation of this map entry. This + * implementation returns the string representation of this + * entry's key followed by the equals character ("=") + * followed by the string representation of this entry's value. + * + * @return a String representation of this map entry + */ + public String toString() { + return key + "=" + value; + } + + } + +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/AbstractSet7.java b/src/ooxml/java/org/apache/poi/util/java7_util/AbstractSet7.java new file mode 100644 index 000000000..bb4fe0011 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/java7_util/AbstractSet7.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.apache.poi.util.java7_util; + +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +/** + * This class provides a skeletal implementation of the Set + * interface to minimize the effort required to implement this + * interface.

+ * + * The process of implementing a set by extending this class is identical + * to that of implementing a Collection by extending AbstractCollection, + * except that all of the methods and constructors in subclasses of this + * class must obey the additional constraints imposed by the Set + * interface (for instance, the add method must not permit addition of + * multiple instances of an object to a set).

+ * + * Note that this class does not override any of the implementations from + * the AbstractCollection class. It merely adds implementations + * for equals and hashCode.

+ * + * This class is a member of the + * + * Java Collections Framework. + * + * @param the type of elements maintained by this set + * + * @author Josh Bloch + * @author Neal Gafter + * @see Collection + * @see AbstractCollection + * @see Set + * @since 1.2 + */ + +public abstract class AbstractSet7 extends AbstractCollection implements Set { + /** + * Sole constructor. (For invocation by subclass constructors, typically + * implicit.) + */ + protected AbstractSet7() { + } + + // Comparison and hashing + + /** + * Compares the specified object with this set for equality. Returns + * true if the given object is also a set, the two sets have + * the same size, and every member of the given set is contained in + * this set. This ensures that the equals method works + * properly across different implementations of the Set + * interface.

+ * + * This implementation first checks if the specified object is this + * set; if so it returns true. Then, it checks if the + * specified object is a set whose size is identical to the size of + * this set; if not, it returns false. If so, it returns + * containsAll((Collection) o). + * + * @param o object to be compared for equality with this set + * @return true if the specified object is equal to this set + */ + public boolean equals(Object o) { + if (o == this) + return true; + + if (!(o instanceof Set)) + return false; + Collection c = (Collection) o; + if (c.size() != size()) + return false; + try { + return containsAll(c); + } catch (ClassCastException unused) { + return false; + } catch (NullPointerException unused) { + return false; + } + } + + /** + * Returns the hash code value for this set. The hash code of a set is + * defined to be the sum of the hash codes of the elements in the set, + * where the hash code of a null element is defined to be zero. + * This ensures that s1.equals(s2) implies that + * s1.hashCode()==s2.hashCode() for any two sets s1 + * and s2, as required by the general contract of + * {@link Object#hashCode}. + * + *

This implementation iterates over the set, calling the + * hashCode method on each element in the set, and adding up + * the results. + * + * @return the hash code value for this set + * @see Object#equals(Object) + * @see Set#equals(Object) + */ + public int hashCode() { + int h = 0; + Iterator i = iterator(); + while (i.hasNext()) { + E obj = i.next(); + if (obj != null) + h += obj.hashCode(); + } + return h; + } + + /** + * Removes from this set all of its elements that are contained in the + * specified collection (optional operation). If the specified + * collection is also a set, this operation effectively modifies this + * set so that its value is the asymmetric set difference of + * the two sets. + * + *

This implementation determines which is the smaller of this set + * and the specified collection, by invoking the size + * method on each. If this set has fewer elements, then the + * implementation iterates over this set, checking each element + * returned by the iterator in turn to see if it is contained in + * the specified collection. If it is so contained, it is removed + * from this set with the iterator's remove method. If + * the specified collection has fewer elements, then the + * implementation iterates over the specified collection, removing + * from this set each element returned by the iterator, using this + * set's remove method. + * + *

Note that this implementation will throw an + * UnsupportedOperationException if the iterator returned by the + * iterator method does not implement the remove method. + * + * @param c collection containing elements to be removed from this set + * @return true if this set changed as a result of the call + * @throws UnsupportedOperationException if the removeAll operation + * is not supported by this set + * @throws ClassCastException if the class of an element of this set + * is incompatible with the specified collection + * (optional) + * @throws NullPointerException if this set contains a null element and the + * specified collection does not permit null elements + * (optional), + * or if the specified collection is null + * @see #remove(Object) + * @see #contains(Object) + */ + public boolean removeAll(Collection c) { + boolean modified = false; + + if (size() > c.size()) { + for (Iterator i = c.iterator(); i.hasNext(); ) + modified |= remove(i.next()); + } else { + for (Iterator i = iterator(); i.hasNext(); ) { + if (c.contains(i.next())) { + i.remove(); + modified = true; + } + } + } + return modified; + } + +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/NavigableMap7.java b/src/ooxml/java/org/apache/poi/util/java7_util/NavigableMap7.java new file mode 100644 index 000000000..45150d5b7 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/java7_util/NavigableMap7.java @@ -0,0 +1,429 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Josh Bloch with assistance from members of JCP + * JSR-166 Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package org.apache.poi.util.java7_util; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Map; +import java.util.SortedMap; + +/** + * A {@link SortedMap} extended with navigation methods returning the + * closest matches for given search targets. Methods + * {@code lowerEntry}, {@code floorEntry}, {@code ceilingEntry}, + * and {@code higherEntry} return {@code Map.Entry} objects + * associated with keys respectively less than, less than or equal, + * greater than or equal, and greater than a given key, returning + * {@code null} if there is no such key. Similarly, methods + * {@code lowerKey}, {@code floorKey}, {@code ceilingKey}, and + * {@code higherKey} return only the associated keys. All of these + * methods are designed for locating, not traversing entries. + * + *

A {@code NavigableMap7} may be accessed and traversed in either + * ascending or descending key order. The {@code descendingMap} + * method returns a view of the map with the senses of all relational + * and directional methods inverted. The performance of ascending + * operations and views is likely to be faster than that of descending + * ones. Methods {@code subMap}, {@code headMap}, + * and {@code tailMap} differ from the like-named {@code + * SortedMap} methods in accepting additional arguments describing + * whether lower and upper bounds are inclusive versus exclusive. + * Submaps of any {@code NavigableMap7} must implement the {@code + * NavigableMap7} interface. + * + *

This interface additionally defines methods {@code firstEntry}, + * {@code pollFirstEntry}, {@code lastEntry}, and + * {@code pollLastEntry} that return and/or remove the least and + * greatest mappings, if any exist, else returning {@code null}. + * + *

Implementations of entry-returning methods are expected to + * return {@code Map.Entry} pairs representing snapshots of mappings + * at the time they were produced, and thus generally do not + * support the optional {@code Entry.setValue} method. Note however + * that it is possible to change mappings in the associated map using + * method {@code put}. + * + *

Methods + * {@link #subMap(Object, Object) subMap(K, K)}, + * {@link #headMap(Object) headMap(K)}, and + * {@link #tailMap(Object) tailMap(K)} + * are specified to return {@code SortedMap} to allow existing + * implementations of {@code SortedMap} to be compatibly retrofitted to + * implement {@code NavigableMap7}, but extensions and implementations + * of this interface are encouraged to override these methods to return + * {@code NavigableMap7}. Similarly, + * {@link #keySet()} can be overriden to return {@code NavigableSet}. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @author Doug Lea + * @author Josh Bloch + * @param the type of keys maintained by this map + * @param the type of mapped values + * @since 1.6 + */ +public interface NavigableMap7 extends SortedMap { + /** + * Returns a key-value mapping associated with the greatest key + * strictly less than the given key, or {@code null} if there is + * no such key. + * + * @param key the key + * @return an entry with the greatest key less than {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + Map.Entry lowerEntry(K key); + + /** + * Returns the greatest key strictly less than the given key, or + * {@code null} if there is no such key. + * + * @param key the key + * @return the greatest key less than {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + K lowerKey(K key); + + /** + * Returns a key-value mapping associated with the greatest key + * less than or equal to the given key, or {@code null} if there + * is no such key. + * + * @param key the key + * @return an entry with the greatest key less than or equal to + * {@code key}, or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + Map.Entry floorEntry(K key); + + /** + * Returns the greatest key less than or equal to the given key, + * or {@code null} if there is no such key. + * + * @param key the key + * @return the greatest key less than or equal to {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + K floorKey(K key); + + /** + * Returns a key-value mapping associated with the least key + * greater than or equal to the given key, or {@code null} if + * there is no such key. + * + * @param key the key + * @return an entry with the least key greater than or equal to + * {@code key}, or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + Map.Entry ceilingEntry(K key); + + /** + * Returns the least key greater than or equal to the given key, + * or {@code null} if there is no such key. + * + * @param key the key + * @return the least key greater than or equal to {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + K ceilingKey(K key); + + /** + * Returns a key-value mapping associated with the least key + * strictly greater than the given key, or {@code null} if there + * is no such key. + * + * @param key the key + * @return an entry with the least key greater than {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + Map.Entry higherEntry(K key); + + /** + * Returns the least key strictly greater than the given key, or + * {@code null} if there is no such key. + * + * @param key the key + * @return the least key greater than {@code key}, + * or {@code null} if there is no such key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map does not permit null keys + */ + K higherKey(K key); + + /** + * Returns a key-value mapping associated with the least + * key in this map, or {@code null} if the map is empty. + * + * @return an entry with the least key, + * or {@code null} if this map is empty + */ + Map.Entry firstEntry(); + + /** + * Returns a key-value mapping associated with the greatest + * key in this map, or {@code null} if the map is empty. + * + * @return an entry with the greatest key, + * or {@code null} if this map is empty + */ + Map.Entry lastEntry(); + + /** + * Removes and returns a key-value mapping associated with + * the least key in this map, or {@code null} if the map is empty. + * + * @return the removed first entry of this map, + * or {@code null} if this map is empty + */ + Map.Entry pollFirstEntry(); + + /** + * Removes and returns a key-value mapping associated with + * the greatest key in this map, or {@code null} if the map is empty. + * + * @return the removed last entry of this map, + * or {@code null} if this map is empty + */ + Map.Entry pollLastEntry(); + + /** + * Returns a reverse order view of the mappings contained in this map. + * The descending map is backed by this map, so changes to the map are + * reflected in the descending map, and vice-versa. If either map is + * modified while an iteration over a collection view of either map + * is in progress (except through the iterator's own {@code remove} + * operation), the results of the iteration are undefined. + * + *

The returned map has an ordering equivalent to + * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator()). + * The expression {@code m.descendingMap().descendingMap()} returns a + * view of {@code m} essentially equivalent to {@code m}. + * + * @return a reverse order view of this map + */ + NavigableMap7 descendingMap(); + + /** + * Returns a {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are reflected in + * the set, and vice-versa. If the map is modified while an iteration + * over the set is in progress (except through the iterator's own {@code + * remove} operation), the results of the iteration are undefined. The + * set supports element removal, which removes the corresponding mapping + * from the map, via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} operations. + * It does not support the {@code add} or {@code addAll} operations. + * + * @return a navigable set view of the keys in this map + */ + NavigableSet7 navigableKeySet(); + + /** + * Returns a reverse order {@link NavigableSet} view of the keys contained in this map. + * The set's iterator returns the keys in descending order. + * The set is backed by the map, so changes to the map are reflected in + * the set, and vice-versa. If the map is modified while an iteration + * over the set is in progress (except through the iterator's own {@code + * remove} operation), the results of the iteration are undefined. The + * set supports element removal, which removes the corresponding mapping + * from the map, via the {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} operations. + * It does not support the {@code add} or {@code addAll} operations. + * + * @return a reverse order navigable set view of the keys in this map + */ + NavigableSet7 descendingKeySet(); + + /** + * Returns a view of the portion of this map whose keys range from + * {@code fromKey} to {@code toKey}. If {@code fromKey} and + * {@code toKey} are equal, the returned map is empty unless + * {@code fromInclusive} and {@code toInclusive} are both true. The + * returned map is backed by this map, so changes in the returned map are + * reflected in this map, and vice-versa. The returned map supports all + * optional map operations that this map supports. + * + *

The returned map will throw an {@code IllegalArgumentException} + * on an attempt to insert a key outside of its range, or to construct a + * submap either of whose endpoints lie outside its range. + * + * @param fromKey low endpoint of the keys in the returned map + * @param fromInclusive {@code true} if the low endpoint + * is to be included in the returned view + * @param toKey high endpoint of the keys in the returned map + * @param toInclusive {@code true} if the high endpoint + * is to be included in the returned view + * @return a view of the portion of this map whose keys range from + * {@code fromKey} to {@code toKey} + * @throws ClassCastException if {@code fromKey} and {@code toKey} + * cannot be compared to one another using this map's comparator + * (or, if the map has no comparator, using natural ordering). + * Implementations may, but are not required to, throw this + * exception if {@code fromKey} or {@code toKey} + * cannot be compared to keys currently in the map. + * @throws NullPointerException if {@code fromKey} or {@code toKey} + * is null and this map does not permit null keys + * @throws IllegalArgumentException if {@code fromKey} is greater than + * {@code toKey}; or if this map itself has a restricted + * range, and {@code fromKey} or {@code toKey} lies + * outside the bounds of the range + */ + NavigableMap7 subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive); + + /** + * Returns a view of the portion of this map whose keys are less than (or + * equal to, if {@code inclusive} is true) {@code toKey}. The returned + * map is backed by this map, so changes in the returned map are reflected + * in this map, and vice-versa. The returned map supports all optional + * map operations that this map supports. + * + *

The returned map will throw an {@code IllegalArgumentException} + * on an attempt to insert a key outside its range. + * + * @param toKey high endpoint of the keys in the returned map + * @param inclusive {@code true} if the high endpoint + * is to be included in the returned view + * @return a view of the portion of this map whose keys are less than + * (or equal to, if {@code inclusive} is true) {@code toKey} + * @throws ClassCastException if {@code toKey} is not compatible + * with this map's comparator (or, if the map has no comparator, + * if {@code toKey} does not implement {@link Comparable}). + * Implementations may, but are not required to, throw this + * exception if {@code toKey} cannot be compared to keys + * currently in the map. + * @throws NullPointerException if {@code toKey} is null + * and this map does not permit null keys + * @throws IllegalArgumentException if this map itself has a + * restricted range, and {@code toKey} lies outside the + * bounds of the range + */ + NavigableMap7 headMap(K toKey, boolean inclusive); + + /** + * Returns a view of the portion of this map whose keys are greater than (or + * equal to, if {@code inclusive} is true) {@code fromKey}. The returned + * map is backed by this map, so changes in the returned map are reflected + * in this map, and vice-versa. The returned map supports all optional + * map operations that this map supports. + * + *

The returned map will throw an {@code IllegalArgumentException} + * on an attempt to insert a key outside its range. + * + * @param fromKey low endpoint of the keys in the returned map + * @param inclusive {@code true} if the low endpoint + * is to be included in the returned view + * @return a view of the portion of this map whose keys are greater than + * (or equal to, if {@code inclusive} is true) {@code fromKey} + * @throws ClassCastException if {@code fromKey} is not compatible + * with this map's comparator (or, if the map has no comparator, + * if {@code fromKey} does not implement {@link Comparable}). + * Implementations may, but are not required to, throw this + * exception if {@code fromKey} cannot be compared to keys + * currently in the map. + * @throws NullPointerException if {@code fromKey} is null + * and this map does not permit null keys + * @throws IllegalArgumentException if this map itself has a + * restricted range, and {@code fromKey} lies outside the + * bounds of the range + */ + NavigableMap7 tailMap(K fromKey, boolean inclusive); + + /** + * {@inheritDoc} + * + *

Equivalent to {@code subMap(fromKey, true, toKey, false)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedMap subMap(K fromKey, K toKey); + + /** + * {@inheritDoc} + * + *

Equivalent to {@code headMap(toKey, false)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedMap headMap(K toKey); + + /** + * {@inheritDoc} + * + *

Equivalent to {@code tailMap(fromKey, true)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedMap tailMap(K fromKey); +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/NavigableSet7.java b/src/ooxml/java/org/apache/poi/util/java7_util/NavigableSet7.java new file mode 100644 index 000000000..bc515e727 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/java7_util/NavigableSet7.java @@ -0,0 +1,324 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Josh Bloch with assistance from members of JCP + * JSR-166 Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package org.apache.poi.util.java7_util; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.SortedSet; + +/** + * A {@link SortedSet} extended with navigation methods reporting + * closest matches for given search targets. Methods {@code lower}, + * {@code floor}, {@code ceiling}, and {@code higher} return elements + * respectively less than, less than or equal, greater than or equal, + * and greater than a given element, returning {@code null} if there + * is no such element. A {@code NavigableSet7} may be accessed and + * traversed in either ascending or descending order. The {@code + * descendingSet} method returns a view of the set with the senses of + * all relational and directional methods inverted. The performance of + * ascending operations and views is likely to be faster than that of + * descending ones. This interface additionally defines methods + * {@code pollFirst} and {@code pollLast} that return and remove the + * lowest and highest element, if one exists, else returning {@code + * null}. Methods {@code subSet}, {@code headSet}, + * and {@code tailSet} differ from the like-named {@code + * SortedSet} methods in accepting additional arguments describing + * whether lower and upper bounds are inclusive versus exclusive. + * Subsets of any {@code NavigableSet7} must implement the {@code + * NavigableSet7} interface. + * + *

The return values of navigation methods may be ambiguous in + * implementations that permit {@code null} elements. However, even + * in this case the result can be disambiguated by checking + * {@code contains(null)}. To avoid such issues, implementations of + * this interface are encouraged to not permit insertion of + * {@code null} elements. (Note that sorted sets of {@link + * Comparable} elements intrinsically do not permit {@code null}.) + * + *

Methods + * {@link #subSet(Object, Object) subSet(E, E)}, + * {@link #headSet(Object) headSet(E)}, and + * {@link #tailSet(Object) tailSet(E)} + * are specified to return {@code SortedSet} to allow existing + * implementations of {@code SortedSet} to be compatibly retrofitted to + * implement {@code NavigableSet7}, but extensions and implementations + * of this interface are encouraged to override these methods to return + * {@code NavigableSet7}. + * + *

This interface is a member of the + * + * Java Collections Framework. + * + * @author Doug Lea + * @author Josh Bloch + * @param the type of elements maintained by this set + * @since 1.6 + */ +public interface NavigableSet7 extends SortedSet { + /** + * Returns the greatest element in this set strictly less than the + * given element, or {@code null} if there is no such element. + * + * @param e the value to match + * @return the greatest element less than {@code e}, + * or {@code null} if there is no such element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set does not permit null elements + */ + E lower(E e); + + /** + * Returns the greatest element in this set less than or equal to + * the given element, or {@code null} if there is no such element. + * + * @param e the value to match + * @return the greatest element less than or equal to {@code e}, + * or {@code null} if there is no such element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set does not permit null elements + */ + E floor(E e); + + /** + * Returns the least element in this set greater than or equal to + * the given element, or {@code null} if there is no such element. + * + * @param e the value to match + * @return the least element greater than or equal to {@code e}, + * or {@code null} if there is no such element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set does not permit null elements + */ + E ceiling(E e); + + /** + * Returns the least element in this set strictly greater than the + * given element, or {@code null} if there is no such element. + * + * @param e the value to match + * @return the least element greater than {@code e}, + * or {@code null} if there is no such element + * @throws ClassCastException if the specified element cannot be + * compared with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set does not permit null elements + */ + E higher(E e); + + /** + * Retrieves and removes the first (lowest) element, + * or returns {@code null} if this set is empty. + * + * @return the first element, or {@code null} if this set is empty + */ + E pollFirst(); + + /** + * Retrieves and removes the last (highest) element, + * or returns {@code null} if this set is empty. + * + * @return the last element, or {@code null} if this set is empty + */ + E pollLast(); + + /** + * Returns an iterator over the elements in this set, in ascending order. + * + * @return an iterator over the elements in this set, in ascending order + */ + Iterator iterator(); + + /** + * Returns a reverse order view of the elements contained in this set. + * The descending set is backed by this set, so changes to the set are + * reflected in the descending set, and vice-versa. If either set is + * modified while an iteration over either set is in progress (except + * through the iterator's own {@code remove} operation), the results of + * the iteration are undefined. + * + *

The returned set has an ordering equivalent to + * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator()). + * The expression {@code s.descendingSet().descendingSet()} returns a + * view of {@code s} essentially equivalent to {@code s}. + * + * @return a reverse order view of this set + */ + NavigableSet7 descendingSet(); + + /** + * Returns an iterator over the elements in this set, in descending order. + * Equivalent in effect to {@code descendingSet().iterator()}. + * + * @return an iterator over the elements in this set, in descending order + */ + Iterator descendingIterator(); + + /** + * Returns a view of the portion of this set whose elements range from + * {@code fromElement} to {@code toElement}. If {@code fromElement} and + * {@code toElement} are equal, the returned set is empty unless {@code + * fromInclusive} and {@code toInclusive} are both true. The returned set + * is backed by this set, so changes in the returned set are reflected in + * this set, and vice-versa. The returned set supports all optional set + * operations that this set supports. + * + *

The returned set will throw an {@code IllegalArgumentException} + * on an attempt to insert an element outside its range. + * + * @param fromElement low endpoint of the returned set + * @param fromInclusive {@code true} if the low endpoint + * is to be included in the returned view + * @param toElement high endpoint of the returned set + * @param toInclusive {@code true} if the high endpoint + * is to be included in the returned view + * @return a view of the portion of this set whose elements range from + * {@code fromElement}, inclusive, to {@code toElement}, exclusive + * @throws ClassCastException if {@code fromElement} and + * {@code toElement} cannot be compared to one another using this + * set's comparator (or, if the set has no comparator, using + * natural ordering). Implementations may, but are not required + * to, throw this exception if {@code fromElement} or + * {@code toElement} cannot be compared to elements currently in + * the set. + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null and this set does + * not permit null elements + * @throws IllegalArgumentException if {@code fromElement} is + * greater than {@code toElement}; or if this set itself + * has a restricted range, and {@code fromElement} or + * {@code toElement} lies outside the bounds of the range. + */ + NavigableSet7 subSet(E fromElement, boolean fromInclusive, + E toElement, boolean toInclusive); + + /** + * Returns a view of the portion of this set whose elements are less than + * (or equal to, if {@code inclusive} is true) {@code toElement}. The + * returned set is backed by this set, so changes in the returned set are + * reflected in this set, and vice-versa. The returned set supports all + * optional set operations that this set supports. + * + *

The returned set will throw an {@code IllegalArgumentException} + * on an attempt to insert an element outside its range. + * + * @param toElement high endpoint of the returned set + * @param inclusive {@code true} if the high endpoint + * is to be included in the returned view + * @return a view of the portion of this set whose elements are less than + * (or equal to, if {@code inclusive} is true) {@code toElement} + * @throws ClassCastException if {@code toElement} is not compatible + * with this set's comparator (or, if the set has no comparator, + * if {@code toElement} does not implement {@link Comparable}). + * Implementations may, but are not required to, throw this + * exception if {@code toElement} cannot be compared to elements + * currently in the set. + * @throws NullPointerException if {@code toElement} is null and + * this set does not permit null elements + * @throws IllegalArgumentException if this set itself has a + * restricted range, and {@code toElement} lies outside the + * bounds of the range + */ + NavigableSet7 headSet(E toElement, boolean inclusive); + + /** + * Returns a view of the portion of this set whose elements are greater + * than (or equal to, if {@code inclusive} is true) {@code fromElement}. + * The returned set is backed by this set, so changes in the returned set + * are reflected in this set, and vice-versa. The returned set supports + * all optional set operations that this set supports. + * + *

The returned set will throw an {@code IllegalArgumentException} + * on an attempt to insert an element outside its range. + * + * @param fromElement low endpoint of the returned set + * @param inclusive {@code true} if the low endpoint + * is to be included in the returned view + * @return a view of the portion of this set whose elements are greater + * than or equal to {@code fromElement} + * @throws ClassCastException if {@code fromElement} is not compatible + * with this set's comparator (or, if the set has no comparator, + * if {@code fromElement} does not implement {@link Comparable}). + * Implementations may, but are not required to, throw this + * exception if {@code fromElement} cannot be compared to elements + * currently in the set. + * @throws NullPointerException if {@code fromElement} is null + * and this set does not permit null elements + * @throws IllegalArgumentException if this set itself has a + * restricted range, and {@code fromElement} lies outside the + * bounds of the range + */ + NavigableSet7 tailSet(E fromElement, boolean inclusive); + + /** + * {@inheritDoc} + * + *

Equivalent to {@code subSet(fromElement, true, toElement, false)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedSet subSet(E fromElement, E toElement); + + /** + * {@inheritDoc} + * + *

Equivalent to {@code headSet(toElement, false)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} +na */ + SortedSet headSet(E toElement); + + /** + * {@inheritDoc} + * + *

Equivalent to {@code tailSet(fromElement, true)}. + * + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws IllegalArgumentException {@inheritDoc} + */ + SortedSet tailSet(E fromElement); +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/TreeMap7.java b/src/ooxml/java/org/apache/poi/util/java7_util/TreeMap7.java new file mode 100644 index 000000000..591d8fb6d --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/java7_util/TreeMap7.java @@ -0,0 +1,2458 @@ +/* + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.apache.poi.util.java7_util; + +import java.io.IOException; +import java.util.AbstractCollection; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.ConcurrentModificationException; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; + +/** + * A Red-Black tree based {@link NavigableMap7} implementation. + * The map is sorted according to the {@linkplain Comparable natural + * ordering} of its keys, or by a {@link Comparator} provided at map + * creation time, depending on which constructor is used. + * + *

This implementation provides guaranteed log(n) time cost for the + * {@code containsKey}, {@code get}, {@code put} and {@code remove} + * operations. Algorithms are adaptations of those in Cormen, Leiserson, and + * Rivest's Introduction to Algorithms. + * + *

Note that the ordering maintained by a tree map, like any sorted map, and + * whether or not an explicit comparator is provided, must be consistent + * with {@code equals} if this sorted map is to correctly implement the + * {@code Map} interface. (See {@code Comparable} or {@code Comparator} for a + * precise definition of consistent with equals.) This is so because + * the {@code Map} interface is defined in terms of the {@code equals} + * operation, but a sorted map performs all key comparisons using its {@code + * compareTo} (or {@code compare}) method, so two keys that are deemed equal by + * this method are, from the standpoint of the sorted map, equal. The behavior + * of a sorted map is well-defined even if its ordering is + * inconsistent with {@code equals}; it just fails to obey the general contract + * of the {@code Map} interface. + * + *

Note that this implementation is not synchronized. + * If multiple threads access a map concurrently, and at least one of the + * threads modifies the map structurally, it must be synchronized + * externally. (A structural modification is any operation that adds or + * deletes one or more mappings; merely changing the value associated + * with an existing key is not a structural modification.) This is + * typically accomplished by synchronizing on some object that naturally + * encapsulates the map. + * If no such object exists, the map should be "wrapped" using the + * {@link Collections#synchronizedSortedMap Collections.synchronizedSortedMap} + * method. This is best done at creation time, to prevent accidental + * unsynchronized access to the map:

+ *   SortedMap m = Collections.synchronizedSortedMap(new TreeMap7(...));
+ * + *

The iterators returned by the {@code iterator} method of the collections + * returned by all of this class's "collection view methods" are + * fail-fast: if the map is structurally modified at any time after + * the iterator is created, in any way except through the iterator's own + * {@code remove} method, the iterator will throw a {@link + * ConcurrentModificationException}. Thus, in the face of concurrent + * modification, the iterator fails quickly and cleanly, rather than risking + * arbitrary, non-deterministic behavior at an undetermined time in the future. + * + *

Note that the fail-fast behavior of an iterator cannot be guaranteed + * as it is, generally speaking, impossible to make any hard guarantees in the + * presence of unsynchronized concurrent modification. Fail-fast iterators + * throw {@code ConcurrentModificationException} on a best-effort basis. + * Therefore, it would be wrong to write a program that depended on this + * exception for its correctness: the fail-fast behavior of iterators + * should be used only to detect bugs. + * + *

All {@code Map.Entry} pairs returned by methods in this class + * and its views represent snapshots of mappings at the time they were + * produced. They do not support the {@code Entry.setValue} + * method. (Note however that it is possible to change mappings in the + * associated map using {@code put}.) + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @param the type of keys maintained by this map + * @param the type of mapped values + * + * @author Josh Bloch and Doug Lea + * @see Map + * @see HashMap + * @see Hashtable + * @see Comparable + * @see Comparator + * @see Collection + * @since 1.2 + */ + +public class TreeMap7 + extends AbstractMap7 + implements NavigableMap7, Cloneable, java.io.Serializable +{ + /** + * The comparator used to maintain order in this tree map, or + * null if it uses the natural ordering of its keys. + * + * @serial + */ + private final Comparator comparator; + + private transient Entry root = null; + + /** + * The number of entries in the tree + */ + private transient int size = 0; + + /** + * The number of structural modifications to the tree. + */ + private transient int modCount = 0; + + /** + * Constructs a new, empty tree map, using the natural ordering of its + * keys. All keys inserted into the map must implement the {@link + * Comparable} interface. Furthermore, all such keys must be + * mutually comparable: {@code k1.compareTo(k2)} must not throw + * a {@code ClassCastException} for any keys {@code k1} and + * {@code k2} in the map. If the user attempts to put a key into the + * map that violates this constraint (for example, the user attempts to + * put a string key into a map whose keys are integers), the + * {@code put(Object key, Object value)} call will throw a + * {@code ClassCastException}. + */ + public TreeMap7() { + comparator = null; + } + + /** + * Constructs a new, empty tree map, ordered according to the given + * comparator. All keys inserted into the map must be mutually + * comparable by the given comparator: {@code comparator.compare(k1, + * k2)} must not throw a {@code ClassCastException} for any keys + * {@code k1} and {@code k2} in the map. If the user attempts to put + * a key into the map that violates this constraint, the {@code put(Object + * key, Object value)} call will throw a + * {@code ClassCastException}. + * + * @param comparator the comparator that will be used to order this map. + * If {@code null}, the {@linkplain Comparable natural + * ordering} of the keys will be used. + */ + public TreeMap7(Comparator comparator) { + this.comparator = comparator; + } + + /** + * Constructs a new tree map containing the same mappings as the given + * map, ordered according to the natural ordering of its keys. + * All keys inserted into the new map must implement the {@link + * Comparable} interface. Furthermore, all such keys must be + * mutually comparable: {@code k1.compareTo(k2)} must not throw + * a {@code ClassCastException} for any keys {@code k1} and + * {@code k2} in the map. This method runs in n*log(n) time. + * + * @param m the map whose mappings are to be placed in this map + * @throws ClassCastException if the keys in m are not {@link Comparable}, + * or are not mutually comparable + * @throws NullPointerException if the specified map is null + */ + public TreeMap7(Map m) { + comparator = null; + putAll(m); + } + + /** + * Constructs a new tree map containing the same mappings and + * using the same ordering as the specified sorted map. This + * method runs in linear time. + * + * @param m the sorted map whose mappings are to be placed in this map, + * and whose comparator is to be used to sort this map + * @throws NullPointerException if the specified map is null + */ + public TreeMap7(SortedMap m) { + comparator = m.comparator(); + try { + buildFromSorted(m.size(), m.entrySet().iterator(), null, null); + } catch (java.io.IOException cannotHappen) { + } catch (ClassNotFoundException cannotHappen) { + } + } + + + // Query Operations + + /** + * Returns the number of key-value mappings in this map. + * + * @return the number of key-value mappings in this map + */ + public int size() { + return size; + } + + /** + * Returns {@code true} if this map contains a mapping for the specified + * key. + * + * @param key key whose presence in this map is to be tested + * @return {@code true} if this map contains a mapping for the + * specified key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + */ + public boolean containsKey(Object key) { + return getEntry(key) != null; + } + + /** + * Returns {@code true} if this map maps one or more keys to the + * specified value. More formally, returns {@code true} if and only if + * this map contains at least one mapping to a value {@code v} such + * that {@code (value==null ? v==null : value.equals(v))}. This + * operation will probably require time linear in the map size for + * most implementations. + * + * @param value value whose presence in this map is to be tested + * @return {@code true} if a mapping to {@code value} exists; + * {@code false} otherwise + * @since 1.2 + */ + public boolean containsValue(Object value) { + for (Entry e = getFirstEntry(); e != null; e = successor(e)) + if (valEquals(value, e.value)) + return true; + return false; + } + + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + * + *

More formally, if this map contains a mapping from a key + * {@code k} to a value {@code v} such that {@code key} compares + * equal to {@code k} according to the map's ordering, then this + * method returns {@code v}; otherwise it returns {@code null}. + * (There can be at most one such mapping.) + * + *

A return value of {@code null} does not necessarily + * indicate that the map contains no mapping for the key; it's also + * possible that the map explicitly maps the key to {@code null}. + * The {@link #containsKey containsKey} operation may be used to + * distinguish these two cases. + * + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + */ + public V get(Object key) { + Entry p = getEntry(key); + return (p==null ? null : p.value); + } + + public Comparator comparator() { + return comparator; + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public K firstKey() { + return key(getFirstEntry()); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public K lastKey() { + return key(getLastEntry()); + } + + /** + * Copies all of the mappings from the specified map to this map. + * These mappings replace any mappings that this map had for any + * of the keys currently in the specified map. + * + * @param map mappings to be stored in this map + * @throws ClassCastException if the class of a key or value in + * the specified map prevents it from being stored in this map + * @throws NullPointerException if the specified map is null or + * the specified map contains a null key and this map does not + * permit null keys + */ + public void putAll(Map map) { + int mapSize = map.size(); + if (size==0 && mapSize!=0 && map instanceof SortedMap) { + Comparator c = ((SortedMap)map).comparator(); + if (c == comparator || (c != null && c.equals(comparator))) { + ++modCount; + try { + buildFromSorted(mapSize, map.entrySet().iterator(), + null, null); + } catch (java.io.IOException cannotHappen) { + } catch (ClassNotFoundException cannotHappen) { + } + return; + } + } + super.putAll(map); + } + + /** + * Returns this map's entry for the given key, or {@code null} if the map + * does not contain an entry for the key. + * + * @return this map's entry for the given key, or {@code null} if the map + * does not contain an entry for the key + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + */ + final Entry getEntry(Object key) { + // Offload comparator-based version for sake of performance + if (comparator != null) + return getEntryUsingComparator(key); + if (key == null) + throw new NullPointerException(); + Comparable k = (Comparable) key; + Entry p = root; + while (p != null) { + int cmp = k.compareTo(p.key); + if (cmp < 0) + p = p.left; + else if (cmp > 0) + p = p.right; + else + return p; + } + return null; + } + + /** + * Version of getEntry using comparator. Split off from getEntry + * for performance. (This is not worth doing for most methods, + * that are less dependent on comparator performance, but is + * worthwhile here.) + */ + final Entry getEntryUsingComparator(Object key) { + K k = (K) key; + Comparator cpr = comparator; + if (cpr != null) { + Entry p = root; + while (p != null) { + int cmp = cpr.compare(k, p.key); + if (cmp < 0) + p = p.left; + else if (cmp > 0) + p = p.right; + else + return p; + } + } + return null; + } + + /** + * Gets the entry corresponding to the specified key; if no such entry + * exists, returns the entry for the least key greater than the specified + * key; if no such entry exists (i.e., the greatest key in the Tree is less + * than the specified key), returns {@code null}. + */ + final Entry getCeilingEntry(K key) { + Entry p = root; + while (p != null) { + int cmp = compare(key, p.key); + if (cmp < 0) { + if (p.left != null) + p = p.left; + else + return p; + } else if (cmp > 0) { + if (p.right != null) { + p = p.right; + } else { + Entry parent = p.parent; + Entry ch = p; + while (parent != null && ch == parent.right) { + ch = parent; + parent = parent.parent; + } + return parent; + } + } else + return p; + } + return null; + } + + /** + * Gets the entry corresponding to the specified key; if no such entry + * exists, returns the entry for the greatest key less than the specified + * key; if no such entry exists, returns {@code null}. + */ + final Entry getFloorEntry(K key) { + Entry p = root; + while (p != null) { + int cmp = compare(key, p.key); + if (cmp > 0) { + if (p.right != null) + p = p.right; + else + return p; + } else if (cmp < 0) { + if (p.left != null) { + p = p.left; + } else { + Entry parent = p.parent; + Entry ch = p; + while (parent != null && ch == parent.left) { + ch = parent; + parent = parent.parent; + } + return parent; + } + } else + return p; + + } + return null; + } + + /** + * Gets the entry for the least key greater than the specified + * key; if no such entry exists, returns the entry for the least + * key greater than the specified key; if no such entry exists + * returns {@code null}. + */ + final Entry getHigherEntry(K key) { + Entry p = root; + while (p != null) { + int cmp = compare(key, p.key); + if (cmp < 0) { + if (p.left != null) + p = p.left; + else + return p; + } else { + if (p.right != null) { + p = p.right; + } else { + Entry parent = p.parent; + Entry ch = p; + while (parent != null && ch == parent.right) { + ch = parent; + parent = parent.parent; + } + return parent; + } + } + } + return null; + } + + /** + * Returns the entry for the greatest key less than the specified key; if + * no such entry exists (i.e., the least key in the Tree is greater than + * the specified key), returns {@code null}. + */ + final Entry getLowerEntry(K key) { + Entry p = root; + while (p != null) { + int cmp = compare(key, p.key); + if (cmp > 0) { + if (p.right != null) + p = p.right; + else + return p; + } else { + if (p.left != null) { + p = p.left; + } else { + Entry parent = p.parent; + Entry ch = p; + while (parent != null && ch == parent.left) { + ch = parent; + parent = parent.parent; + } + return parent; + } + } + } + return null; + } + + /** + * Associates the specified value with the specified key in this map. + * If the map previously contained a mapping for the key, the old + * value is replaced. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key}. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with {@code key}.) + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + */ + public V put(K key, V value) { + Entry t = root; + if (t == null) { + compare(key, key); // type (and possibly null) check + + root = new Entry(key, value, null); + size = 1; + modCount++; + return null; + } + int cmp; + Entry parent; + // split comparator and comparable paths + Comparator cpr = comparator; + if (cpr != null) { + do { + parent = t; + cmp = cpr.compare(key, t.key); + if (cmp < 0) + t = t.left; + else if (cmp > 0) + t = t.right; + else + return t.setValue(value); + } while (t != null); + } + else { + if (key == null) + throw new NullPointerException(); + Comparable k = (Comparable) key; + do { + parent = t; + cmp = k.compareTo(t.key); + if (cmp < 0) + t = t.left; + else if (cmp > 0) + t = t.right; + else + return t.setValue(value); + } while (t != null); + } + Entry e = new Entry(key, value, parent); + if (cmp < 0) + parent.left = e; + else + parent.right = e; + fixAfterInsertion(e); + size++; + modCount++; + return null; + } + + /** + * Removes the mapping for this key from this TreeMap7 if present. + * + * @param key key for which mapping should be removed + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key}. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with {@code key}.) + * @throws ClassCastException if the specified key cannot be compared + * with the keys currently in the map + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + */ + public V remove(Object key) { + Entry p = getEntry(key); + if (p == null) + return null; + + V oldValue = p.value; + deleteEntry(p); + return oldValue; + } + + /** + * Removes all of the mappings from this map. + * The map will be empty after this call returns. + */ + public void clear() { + modCount++; + size = 0; + root = null; + } + + /** + * Returns a shallow copy of this {@code TreeMap7} instance. (The keys and + * values themselves are not cloned.) + * + * @return a shallow copy of this map + */ + public Object clone() { + TreeMap7 clone = null; + try { + clone = (TreeMap7) super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + + // Put clone into "virgin" state (except for comparator) + clone.root = null; + clone.size = 0; + clone.modCount = 0; + clone.entrySet = null; + clone.navigableKeySet = null; + clone.descendingMap = null; + + // Initialize clone with our mappings + try { + clone.buildFromSorted(size, entrySet().iterator(), null, null); + } catch (java.io.IOException cannotHappen) { + } catch (ClassNotFoundException cannotHappen) { + } + + return clone; + } + + // NavigableMap7 API methods + + /** + * @since 1.6 + */ + public Map.Entry firstEntry() { + return exportEntry(getFirstEntry()); + } + + /** + * @since 1.6 + */ + public Map.Entry lastEntry() { + return exportEntry(getLastEntry()); + } + + /** + * @since 1.6 + */ + public Map.Entry pollFirstEntry() { + Entry p = getFirstEntry(); + Map.Entry result = exportEntry(p); + if (p != null) + deleteEntry(p); + return result; + } + + /** + * @since 1.6 + */ + public Map.Entry pollLastEntry() { + Entry p = getLastEntry(); + Map.Entry result = exportEntry(p); + if (p != null) + deleteEntry(p); + return result; + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public Map.Entry lowerEntry(K key) { + return exportEntry(getLowerEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public K lowerKey(K key) { + return keyOrNull(getLowerEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public Map.Entry floorEntry(K key) { + return exportEntry(getFloorEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public K floorKey(K key) { + return keyOrNull(getFloorEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public Map.Entry ceilingEntry(K key) { + return exportEntry(getCeilingEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public K ceilingKey(K key) { + return keyOrNull(getCeilingEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public Map.Entry higherEntry(K key) { + return exportEntry(getHigherEntry(key)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified key is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @since 1.6 + */ + public K higherKey(K key) { + return keyOrNull(getHigherEntry(key)); + } + + // Views + + /** + * Fields initialized to contain an instance of the entry set view + * the first time this view is requested. Views are stateless, so + * there's no reason to create more than one. + */ + private transient EntrySet entrySet = null; + private transient KeySet navigableKeySet = null; + private transient NavigableMap7 descendingMap = null; + + /** + * Returns a {@link Set} view of the keys contained in this map. + * The set's iterator returns the keys in ascending order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. If the map is modified + * while an iteration over the set is in progress (except through + * the iterator's own {@code remove} operation), the results of + * the iteration are undefined. The set supports element removal, + * which removes the corresponding mapping from the map, via the + * {@code Iterator.remove}, {@code Set.remove}, + * {@code removeAll}, {@code retainAll}, and {@code clear} + * operations. It does not support the {@code add} or {@code addAll} + * operations. + */ + public Set keySet() { + return navigableKeySet(); + } + + /** + * @since 1.6 + */ + public NavigableSet7 navigableKeySet() { + KeySet nks = navigableKeySet; + return (nks != null) ? nks : (navigableKeySet = new KeySet(this)); + } + + /** + * @since 1.6 + */ + public NavigableSet7 descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + /** + * Returns a {@link Collection} view of the values contained in this map. + * The collection's iterator returns the values in ascending order + * of the corresponding keys. + * The collection is backed by the map, so changes to the map are + * reflected in the collection, and vice-versa. If the map is + * modified while an iteration over the collection is in progress + * (except through the iterator's own {@code remove} operation), + * the results of the iteration are undefined. The collection + * supports element removal, which removes the corresponding + * mapping from the map, via the {@code Iterator.remove}, + * {@code Collection.remove}, {@code removeAll}, + * {@code retainAll} and {@code clear} operations. It does not + * support the {@code add} or {@code addAll} operations. + */ + public Collection values() { + Collection vs = values; + return (vs != null) ? vs : (values = new Values()); + } + + /** + * Returns a {@link Set} view of the mappings contained in this map. + * The set's iterator returns the entries in ascending key order. + * The set is backed by the map, so changes to the map are + * reflected in the set, and vice-versa. If the map is modified + * while an iteration over the set is in progress (except through + * the iterator's own {@code remove} operation, or through the + * {@code setValue} operation on a map entry returned by the + * iterator) the results of the iteration are undefined. The set + * supports element removal, which removes the corresponding + * mapping from the map, via the {@code Iterator.remove}, + * {@code Set.remove}, {@code removeAll}, {@code retainAll} and + * {@code clear} operations. It does not support the + * {@code add} or {@code addAll} operations. + */ + public Set> entrySet() { + EntrySet es = entrySet; + return (es != null) ? es : (entrySet = new EntrySet()); + } + + /** + * @since 1.6 + */ + public NavigableMap7 descendingMap() { + NavigableMap7 km = descendingMap; + return (km != null) ? km : + (descendingMap = new DescendingSubMap(this, + true, null, true, + true, null, true)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} or {@code toKey} is + * null and this map uses natural ordering, or its comparator + * does not permit null keys + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + public NavigableMap7 subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive) { + return new AscendingSubMap(this, + false, fromKey, fromInclusive, + false, toKey, toInclusive); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toKey} is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + public NavigableMap7 headMap(K toKey, boolean inclusive) { + return new AscendingSubMap(this, + true, null, true, + false, toKey, inclusive); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + public NavigableMap7 tailMap(K fromKey, boolean inclusive) { + return new AscendingSubMap(this, + false, fromKey, inclusive, + true, null, true); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} or {@code toKey} is + * null and this map uses natural ordering, or its comparator + * does not permit null keys + * @throws IllegalArgumentException {@inheritDoc} + */ + public SortedMap subMap(K fromKey, K toKey) { + return subMap(fromKey, true, toKey, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toKey} is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @throws IllegalArgumentException {@inheritDoc} + */ + public SortedMap headMap(K toKey) { + return headMap(toKey, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromKey} is null + * and this map uses natural ordering, or its comparator + * does not permit null keys + * @throws IllegalArgumentException {@inheritDoc} + */ + public SortedMap tailMap(K fromKey) { + return tailMap(fromKey, true); + } + + // View class support + + class Values extends AbstractCollection { + public Iterator iterator() { + return new ValueIterator(getFirstEntry()); + } + + public int size() { + return TreeMap7.this.size(); + } + + public boolean contains(Object o) { + return TreeMap7.this.containsValue(o); + } + + public boolean remove(Object o) { + for (Entry e = getFirstEntry(); e != null; e = successor(e)) { + if (valEquals(e.getValue(), o)) { + deleteEntry(e); + return true; + } + } + return false; + } + + public void clear() { + TreeMap7.this.clear(); + } + } + + class EntrySet extends AbstractSet> { + public Iterator> iterator() { + return new EntryIterator(getFirstEntry()); + } + + public boolean contains(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry entry = (Map.Entry) o; + V value = entry.getValue(); + Entry p = getEntry(entry.getKey()); + return p != null && valEquals(p.getValue(), value); + } + + public boolean remove(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry entry = (Map.Entry) o; + V value = entry.getValue(); + Entry p = getEntry(entry.getKey()); + if (p != null && valEquals(p.getValue(), value)) { + deleteEntry(p); + return true; + } + return false; + } + + public int size() { + return TreeMap7.this.size(); + } + + public void clear() { + TreeMap7.this.clear(); + } + } + + /* + * Unlike Values and EntrySet, the KeySet class is static, + * delegating to a NavigableMap7 to allow use by SubMaps, which + * outweighs the ugliness of needing type-tests for the following + * Iterator methods that are defined appropriately in main versus + * submap classes. + */ + + Iterator keyIterator() { + return new KeyIterator(getFirstEntry()); + } + + Iterator descendingKeyIterator() { + return new DescendingKeyIterator(getLastEntry()); + } + + static final class KeySet extends AbstractSet implements NavigableSet7 { + private final NavigableMap7 m; + KeySet(NavigableMap7 map) { m = map; } + + public Iterator iterator() { + if (m instanceof TreeMap7) + return ((TreeMap7)m).keyIterator(); + else + return (Iterator)(((TreeMap7.NavigableSubMap)m).keyIterator()); + } + + public Iterator descendingIterator() { + if (m instanceof TreeMap7) + return ((TreeMap7)m).descendingKeyIterator(); + else + return (Iterator)(((TreeMap7.NavigableSubMap)m).descendingKeyIterator()); + } + + public int size() { return m.size(); } + public boolean isEmpty() { return m.isEmpty(); } + public boolean contains(Object o) { return m.containsKey(o); } + public void clear() { m.clear(); } + public E lower(E e) { return m.lowerKey(e); } + public E floor(E e) { return m.floorKey(e); } + public E ceiling(E e) { return m.ceilingKey(e); } + public E higher(E e) { return m.higherKey(e); } + public E first() { return m.firstKey(); } + public E last() { return m.lastKey(); } + public Comparator comparator() { return m.comparator(); } + public E pollFirst() { + Map.Entry e = m.pollFirstEntry(); + return (e == null) ? null : e.getKey(); + } + public E pollLast() { + Map.Entry e = m.pollLastEntry(); + return (e == null) ? null : e.getKey(); + } + public boolean remove(Object o) { + int oldSize = size(); + m.remove(o); + return size() != oldSize; + } + public NavigableSet7 subSet(E fromElement, boolean fromInclusive, + E toElement, boolean toInclusive) { + return new KeySet(m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); + } + public NavigableSet7 headSet(E toElement, boolean inclusive) { + return new KeySet(m.headMap(toElement, inclusive)); + } + public NavigableSet7 tailSet(E fromElement, boolean inclusive) { + return new KeySet(m.tailMap(fromElement, inclusive)); + } + public SortedSet subSet(E fromElement, E toElement) { + return subSet(fromElement, true, toElement, false); + } + public SortedSet headSet(E toElement) { + return headSet(toElement, false); + } + public SortedSet tailSet(E fromElement) { + return tailSet(fromElement, true); + } + public NavigableSet7 descendingSet() { + return new KeySet(m.descendingMap()); + } + } + + /** + * Base class for TreeMap7 Iterators + */ + abstract class PrivateEntryIterator implements Iterator { + Entry next; + Entry lastReturned; + int expectedModCount; + + PrivateEntryIterator(Entry first) { + expectedModCount = modCount; + lastReturned = null; + next = first; + } + + public final boolean hasNext() { + return next != null; + } + + final Entry nextEntry() { + Entry e = next; + if (e == null) + throw new NoSuchElementException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + next = successor(e); + lastReturned = e; + return e; + } + + final Entry prevEntry() { + Entry e = next; + if (e == null) + throw new NoSuchElementException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + next = predecessor(e); + lastReturned = e; + return e; + } + + public void remove() { + if (lastReturned == null) + throw new IllegalStateException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + // deleted entries are replaced by their successors + if (lastReturned.left != null && lastReturned.right != null) + next = lastReturned; + deleteEntry(lastReturned); + expectedModCount = modCount; + lastReturned = null; + } + } + + final class EntryIterator extends PrivateEntryIterator> { + EntryIterator(Entry first) { + super(first); + } + public Map.Entry next() { + return nextEntry(); + } + } + + final class ValueIterator extends PrivateEntryIterator { + ValueIterator(Entry first) { + super(first); + } + public V next() { + return nextEntry().value; + } + } + + final class KeyIterator extends PrivateEntryIterator { + KeyIterator(Entry first) { + super(first); + } + public K next() { + return nextEntry().key; + } + } + + final class DescendingKeyIterator extends PrivateEntryIterator { + DescendingKeyIterator(Entry first) { + super(first); + } + public K next() { + return prevEntry().key; + } + } + + // Little utilities + + /** + * Compares two keys using the correct comparison method for this TreeMap7. + */ + final int compare(Object k1, Object k2) { + return comparator==null ? ((Comparable)k1).compareTo((K)k2) + : comparator.compare((K)k1, (K)k2); + } + + /** + * Test two values for equality. Differs from o1.equals(o2) only in + * that it copes with {@code null} o1 properly. + */ + static final boolean valEquals(Object o1, Object o2) { + return (o1==null ? o2==null : o1.equals(o2)); + } + + /** + * Return SimpleImmutableEntry for entry, or null if null + */ + static Map.Entry exportEntry(TreeMap7.Entry e) { + return (e == null) ? null : + new AbstractMap7.SimpleImmutableEntry(e); + } + + /** + * Return key for entry, or null if null + */ + static K keyOrNull(TreeMap7.Entry e) { + return (e == null) ? null : e.key; + } + + /** + * Returns the key corresponding to the specified Entry. + * @throws NoSuchElementException if the Entry is null + */ + static K key(Entry e) { + if (e==null) + throw new NoSuchElementException(); + return e.key; + } + + + // SubMaps + + /** + * Dummy value serving as unmatchable fence key for unbounded + * SubMapIterators + */ + private static final Object UNBOUNDED = new Object(); + + /** + * @serial include + */ + abstract static class NavigableSubMap extends AbstractMap7 + implements NavigableMap7, java.io.Serializable { + /** + * The backing map. + */ + final TreeMap7 m; + + /** + * Endpoints are represented as triples (fromStart, lo, + * loInclusive) and (toEnd, hi, hiInclusive). If fromStart is + * true, then the low (absolute) bound is the start of the + * backing map, and the other values are ignored. Otherwise, + * if loInclusive is true, lo is the inclusive bound, else lo + * is the exclusive bound. Similarly for the upper bound. + */ + final K lo, hi; + final boolean fromStart, toEnd; + final boolean loInclusive, hiInclusive; + + NavigableSubMap(TreeMap7 m, + boolean fromStart, K lo, boolean loInclusive, + boolean toEnd, K hi, boolean hiInclusive) { + if (!fromStart && !toEnd) { + if (m.compare(lo, hi) > 0) + throw new IllegalArgumentException("fromKey > toKey"); + } else { + if (!fromStart) // type check + m.compare(lo, lo); + if (!toEnd) + m.compare(hi, hi); + } + + this.m = m; + this.fromStart = fromStart; + this.lo = lo; + this.loInclusive = loInclusive; + this.toEnd = toEnd; + this.hi = hi; + this.hiInclusive = hiInclusive; + } + + // internal utilities + + final boolean tooLow(Object key) { + if (!fromStart) { + int c = m.compare(key, lo); + if (c < 0 || (c == 0 && !loInclusive)) + return true; + } + return false; + } + + final boolean tooHigh(Object key) { + if (!toEnd) { + int c = m.compare(key, hi); + if (c > 0 || (c == 0 && !hiInclusive)) + return true; + } + return false; + } + + final boolean inRange(Object key) { + return !tooLow(key) && !tooHigh(key); + } + + final boolean inClosedRange(Object key) { + return (fromStart || m.compare(key, lo) >= 0) + && (toEnd || m.compare(hi, key) >= 0); + } + + final boolean inRange(Object key, boolean inclusive) { + return inclusive ? inRange(key) : inClosedRange(key); + } + + /* + * Absolute versions of relation operations. + * Subclasses map to these using like-named "sub" + * versions that invert senses for descending maps + */ + + final TreeMap7.Entry absLowest() { + TreeMap7.Entry e = + (fromStart ? m.getFirstEntry() : + (loInclusive ? m.getCeilingEntry(lo) : + m.getHigherEntry(lo))); + return (e == null || tooHigh(e.key)) ? null : e; + } + + final TreeMap7.Entry absHighest() { + TreeMap7.Entry e = + (toEnd ? m.getLastEntry() : + (hiInclusive ? m.getFloorEntry(hi) : + m.getLowerEntry(hi))); + return (e == null || tooLow(e.key)) ? null : e; + } + + final TreeMap7.Entry absCeiling(K key) { + if (tooLow(key)) + return absLowest(); + TreeMap7.Entry e = m.getCeilingEntry(key); + return (e == null || tooHigh(e.key)) ? null : e; + } + + final TreeMap7.Entry absHigher(K key) { + if (tooLow(key)) + return absLowest(); + TreeMap7.Entry e = m.getHigherEntry(key); + return (e == null || tooHigh(e.key)) ? null : e; + } + + final TreeMap7.Entry absFloor(K key) { + if (tooHigh(key)) + return absHighest(); + TreeMap7.Entry e = m.getFloorEntry(key); + return (e == null || tooLow(e.key)) ? null : e; + } + + final TreeMap7.Entry absLower(K key) { + if (tooHigh(key)) + return absHighest(); + TreeMap7.Entry e = m.getLowerEntry(key); + return (e == null || tooLow(e.key)) ? null : e; + } + + /** Returns the absolute high fence for ascending traversal */ + final TreeMap7.Entry absHighFence() { + return (toEnd ? null : (hiInclusive ? + m.getHigherEntry(hi) : + m.getCeilingEntry(hi))); + } + + /** Return the absolute low fence for descending traversal */ + final TreeMap7.Entry absLowFence() { + return (fromStart ? null : (loInclusive ? + m.getLowerEntry(lo) : + m.getFloorEntry(lo))); + } + + // Abstract methods defined in ascending vs descending classes + // These relay to the appropriate absolute versions + + abstract TreeMap7.Entry subLowest(); + abstract TreeMap7.Entry subHighest(); + abstract TreeMap7.Entry subCeiling(K key); + abstract TreeMap7.Entry subHigher(K key); + abstract TreeMap7.Entry subFloor(K key); + abstract TreeMap7.Entry subLower(K key); + + /** Returns ascending iterator from the perspective of this submap */ + abstract Iterator keyIterator(); + + /** Returns descending iterator from the perspective of this submap */ + abstract Iterator descendingKeyIterator(); + + // public methods + + public boolean isEmpty() { + return (fromStart && toEnd) ? m.isEmpty() : entrySet().isEmpty(); + } + + public int size() { + return (fromStart && toEnd) ? m.size() : entrySet().size(); + } + + public final boolean containsKey(Object key) { + return inRange(key) && m.containsKey(key); + } + + public final V put(K key, V value) { + if (!inRange(key)) + throw new IllegalArgumentException("key out of range"); + return m.put(key, value); + } + + public final V get(Object key) { + return !inRange(key) ? null : m.get(key); + } + + public final V remove(Object key) { + return !inRange(key) ? null : m.remove(key); + } + + public final Map.Entry ceilingEntry(K key) { + return exportEntry(subCeiling(key)); + } + + public final K ceilingKey(K key) { + return keyOrNull(subCeiling(key)); + } + + public final Map.Entry higherEntry(K key) { + return exportEntry(subHigher(key)); + } + + public final K higherKey(K key) { + return keyOrNull(subHigher(key)); + } + + public final Map.Entry floorEntry(K key) { + return exportEntry(subFloor(key)); + } + + public final K floorKey(K key) { + return keyOrNull(subFloor(key)); + } + + public final Map.Entry lowerEntry(K key) { + return exportEntry(subLower(key)); + } + + public final K lowerKey(K key) { + return keyOrNull(subLower(key)); + } + + public final K firstKey() { + return key(subLowest()); + } + + public final K lastKey() { + return key(subHighest()); + } + + public final Map.Entry firstEntry() { + return exportEntry(subLowest()); + } + + public final Map.Entry lastEntry() { + return exportEntry(subHighest()); + } + + public final Map.Entry pollFirstEntry() { + TreeMap7.Entry e = subLowest(); + Map.Entry result = exportEntry(e); + if (e != null) + m.deleteEntry(e); + return result; + } + + public final Map.Entry pollLastEntry() { + TreeMap7.Entry e = subHighest(); + Map.Entry result = exportEntry(e); + if (e != null) + m.deleteEntry(e); + return result; + } + + // Views + transient NavigableMap7 descendingMapView = null; + transient EntrySetView entrySetView = null; + transient KeySet navigableKeySetView = null; + + public final NavigableSet7 navigableKeySet() { + KeySet nksv = navigableKeySetView; + return (nksv != null) ? nksv : + (navigableKeySetView = new TreeMap7.KeySet(this)); + } + + public final Set keySet() { + return navigableKeySet(); + } + + public NavigableSet7 descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + public final SortedMap subMap(K fromKey, K toKey) { + return subMap(fromKey, true, toKey, false); + } + + public final SortedMap headMap(K toKey) { + return headMap(toKey, false); + } + + public final SortedMap tailMap(K fromKey) { + return tailMap(fromKey, true); + } + + // View classes + + abstract class EntrySetView extends AbstractSet> { + private transient int size = -1, sizeModCount; + + public int size() { + if (fromStart && toEnd) + return m.size(); + if (size == -1 || sizeModCount != m.modCount) { + sizeModCount = m.modCount; + size = 0; + Iterator i = iterator(); + while (i.hasNext()) { + size++; + i.next(); + } + } + return size; + } + + public boolean isEmpty() { + TreeMap7.Entry n = absLowest(); + return n == null || tooHigh(n.key); + } + + public boolean contains(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry entry = (Map.Entry) o; + K key = entry.getKey(); + if (!inRange(key)) + return false; + TreeMap7.Entry node = m.getEntry(key); + return node != null && + valEquals(node.getValue(), entry.getValue()); + } + + public boolean remove(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry entry = (Map.Entry) o; + K key = entry.getKey(); + if (!inRange(key)) + return false; + TreeMap7.Entry node = m.getEntry(key); + if (node!=null && valEquals(node.getValue(), + entry.getValue())) { + m.deleteEntry(node); + return true; + } + return false; + } + } + + /** + * Iterators for SubMaps + */ + abstract class SubMapIterator implements Iterator { + TreeMap7.Entry lastReturned; + TreeMap7.Entry next; + final Object fenceKey; + int expectedModCount; + + SubMapIterator(TreeMap7.Entry first, + TreeMap7.Entry fence) { + expectedModCount = m.modCount; + lastReturned = null; + next = first; + fenceKey = fence == null ? UNBOUNDED : fence.key; + } + + public final boolean hasNext() { + return next != null && next.key != fenceKey; + } + + final TreeMap7.Entry nextEntry() { + TreeMap7.Entry e = next; + if (e == null || e.key == fenceKey) + throw new NoSuchElementException(); + if (m.modCount != expectedModCount) + throw new ConcurrentModificationException(); + next = successor(e); + lastReturned = e; + return e; + } + + final TreeMap7.Entry prevEntry() { + TreeMap7.Entry e = next; + if (e == null || e.key == fenceKey) + throw new NoSuchElementException(); + if (m.modCount != expectedModCount) + throw new ConcurrentModificationException(); + next = predecessor(e); + lastReturned = e; + return e; + } + + final void removeAscending() { + if (lastReturned == null) + throw new IllegalStateException(); + if (m.modCount != expectedModCount) + throw new ConcurrentModificationException(); + // deleted entries are replaced by their successors + if (lastReturned.left != null && lastReturned.right != null) + next = lastReturned; + m.deleteEntry(lastReturned); + lastReturned = null; + expectedModCount = m.modCount; + } + + final void removeDescending() { + if (lastReturned == null) + throw new IllegalStateException(); + if (m.modCount != expectedModCount) + throw new ConcurrentModificationException(); + m.deleteEntry(lastReturned); + lastReturned = null; + expectedModCount = m.modCount; + } + + } + + final class SubMapEntryIterator extends SubMapIterator> { + SubMapEntryIterator(TreeMap7.Entry first, + TreeMap7.Entry fence) { + super(first, fence); + } + public Map.Entry next() { + return nextEntry(); + } + public void remove() { + removeAscending(); + } + } + + final class SubMapKeyIterator extends SubMapIterator { + SubMapKeyIterator(TreeMap7.Entry first, + TreeMap7.Entry fence) { + super(first, fence); + } + public K next() { + return nextEntry().key; + } + public void remove() { + removeAscending(); + } + } + + final class DescendingSubMapEntryIterator extends SubMapIterator> { + DescendingSubMapEntryIterator(TreeMap7.Entry last, + TreeMap7.Entry fence) { + super(last, fence); + } + + public Map.Entry next() { + return prevEntry(); + } + public void remove() { + removeDescending(); + } + } + + final class DescendingSubMapKeyIterator extends SubMapIterator { + DescendingSubMapKeyIterator(TreeMap7.Entry last, + TreeMap7.Entry fence) { + super(last, fence); + } + public K next() { + return prevEntry().key; + } + public void remove() { + removeDescending(); + } + } + } + + /** + * @serial include + */ + static final class AscendingSubMap extends NavigableSubMap { + private static final long serialVersionUID = 912986545866124060L; + + AscendingSubMap(TreeMap7 m, + boolean fromStart, K lo, boolean loInclusive, + boolean toEnd, K hi, boolean hiInclusive) { + super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive); + } + + public Comparator comparator() { + return m.comparator(); + } + + public NavigableMap7 subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive) { + if (!inRange(fromKey, fromInclusive)) + throw new IllegalArgumentException("fromKey out of range"); + if (!inRange(toKey, toInclusive)) + throw new IllegalArgumentException("toKey out of range"); + return new AscendingSubMap(m, + false, fromKey, fromInclusive, + false, toKey, toInclusive); + } + + public NavigableMap7 headMap(K toKey, boolean inclusive) { + if (!inRange(toKey, inclusive)) + throw new IllegalArgumentException("toKey out of range"); + return new AscendingSubMap(m, + fromStart, lo, loInclusive, + false, toKey, inclusive); + } + + public NavigableMap7 tailMap(K fromKey, boolean inclusive) { + if (!inRange(fromKey, inclusive)) + throw new IllegalArgumentException("fromKey out of range"); + return new AscendingSubMap(m, + false, fromKey, inclusive, + toEnd, hi, hiInclusive); + } + + public NavigableMap7 descendingMap() { + NavigableMap7 mv = descendingMapView; + return (mv != null) ? mv : + (descendingMapView = + new DescendingSubMap(m, + fromStart, lo, loInclusive, + toEnd, hi, hiInclusive)); + } + + Iterator keyIterator() { + return new SubMapKeyIterator(absLowest(), absHighFence()); + } + + Iterator descendingKeyIterator() { + return new DescendingSubMapKeyIterator(absHighest(), absLowFence()); + } + + final class AscendingEntrySetView extends EntrySetView { + public Iterator> iterator() { + return new SubMapEntryIterator(absLowest(), absHighFence()); + } + } + + public Set> entrySet() { + EntrySetView es = entrySetView; + return (es != null) ? es : new AscendingEntrySetView(); + } + + TreeMap7.Entry subLowest() { return absLowest(); } + TreeMap7.Entry subHighest() { return absHighest(); } + TreeMap7.Entry subCeiling(K key) { return absCeiling(key); } + TreeMap7.Entry subHigher(K key) { return absHigher(key); } + TreeMap7.Entry subFloor(K key) { return absFloor(key); } + TreeMap7.Entry subLower(K key) { return absLower(key); } + } + + /** + * @serial include + */ + static final class DescendingSubMap extends NavigableSubMap { + private static final long serialVersionUID = 912986545866120460L; + DescendingSubMap(TreeMap7 m, + boolean fromStart, K lo, boolean loInclusive, + boolean toEnd, K hi, boolean hiInclusive) { + super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive); + } + + private final Comparator reverseComparator = + Collections.reverseOrder(m.comparator); + + public Comparator comparator() { + return reverseComparator; + } + + public NavigableMap7 subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive) { + if (!inRange(fromKey, fromInclusive)) + throw new IllegalArgumentException("fromKey out of range"); + if (!inRange(toKey, toInclusive)) + throw new IllegalArgumentException("toKey out of range"); + return new DescendingSubMap(m, + false, toKey, toInclusive, + false, fromKey, fromInclusive); + } + + public NavigableMap7 headMap(K toKey, boolean inclusive) { + if (!inRange(toKey, inclusive)) + throw new IllegalArgumentException("toKey out of range"); + return new DescendingSubMap(m, + false, toKey, inclusive, + toEnd, hi, hiInclusive); + } + + public NavigableMap7 tailMap(K fromKey, boolean inclusive) { + if (!inRange(fromKey, inclusive)) + throw new IllegalArgumentException("fromKey out of range"); + return new DescendingSubMap(m, + fromStart, lo, loInclusive, + false, fromKey, inclusive); + } + + public NavigableMap7 descendingMap() { + NavigableMap7 mv = descendingMapView; + return (mv != null) ? mv : + (descendingMapView = + new AscendingSubMap(m, + fromStart, lo, loInclusive, + toEnd, hi, hiInclusive)); + } + + Iterator keyIterator() { + return new DescendingSubMapKeyIterator(absHighest(), absLowFence()); + } + + Iterator descendingKeyIterator() { + return new SubMapKeyIterator(absLowest(), absHighFence()); + } + + final class DescendingEntrySetView extends EntrySetView { + public Iterator> iterator() { + return new DescendingSubMapEntryIterator(absHighest(), absLowFence()); + } + } + + public Set> entrySet() { + EntrySetView es = entrySetView; + return (es != null) ? es : new DescendingEntrySetView(); + } + + TreeMap7.Entry subLowest() { return absHighest(); } + TreeMap7.Entry subHighest() { return absLowest(); } + TreeMap7.Entry subCeiling(K key) { return absFloor(key); } + TreeMap7.Entry subHigher(K key) { return absLower(key); } + TreeMap7.Entry subFloor(K key) { return absCeiling(key); } + TreeMap7.Entry subLower(K key) { return absHigher(key); } + } + + /** + * This class exists solely for the sake of serialization + * compatibility with previous releases of TreeMap7 that did not + * support NavigableMap7. It translates an old-version SubMap into + * a new-version AscendingSubMap. This class is never otherwise + * used. + * + * @serial include + */ + private class SubMap extends AbstractMap7 + implements SortedMap, java.io.Serializable { + private static final long serialVersionUID = -6520786458950516097L; + private boolean fromStart = false, toEnd = false; + private K fromKey, toKey; + private Object readResolve() { + return new AscendingSubMap(TreeMap7.this, + fromStart, fromKey, true, + toEnd, toKey, false); + } + public Set> entrySet() { throw new InternalError(); } + public K lastKey() { throw new InternalError(); } + public K firstKey() { throw new InternalError(); } + public SortedMap subMap(K fromKey, K toKey) { throw new InternalError(); } + public SortedMap headMap(K toKey) { throw new InternalError(); } + public SortedMap tailMap(K fromKey) { throw new InternalError(); } + public Comparator comparator() { throw new InternalError(); } + } + + + // Red-black mechanics + + private static final boolean RED = false; + private static final boolean BLACK = true; + + /** + * Node in the Tree. Doubles as a means to pass key-value pairs back to + * user (see Map.Entry). + */ + + static final class Entry implements Map.Entry { + K key; + V value; + Entry left = null; + Entry right = null; + Entry parent; + boolean color = BLACK; + + /** + * Make a new cell with given key, value, and parent, and with + * {@code null} child links, and BLACK color. + */ + Entry(K key, V value, Entry parent) { + this.key = key; + this.value = value; + this.parent = parent; + } + + /** + * Returns the key. + * + * @return the key + */ + public K getKey() { + return key; + } + + /** + * Returns the value associated with the key. + * + * @return the value associated with the key + */ + public V getValue() { + return value; + } + + /** + * Replaces the value currently associated with the key with the given + * value. + * + * @return the value associated with the key before this method was + * called + */ + public V setValue(V value) { + V oldValue = this.value; + this.value = value; + return oldValue; + } + + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + + return valEquals(key,e.getKey()) && valEquals(value,e.getValue()); + } + + public int hashCode() { + int keyHash = (key==null ? 0 : key.hashCode()); + int valueHash = (value==null ? 0 : value.hashCode()); + return keyHash ^ valueHash; + } + + public String toString() { + return key + "=" + value; + } + } + + /** + * Returns the first Entry in the TreeMap7 (according to the TreeMap7's + * key-sort function). Returns null if the TreeMap7 is empty. + */ + final Entry getFirstEntry() { + Entry p = root; + if (p != null) + while (p.left != null) + p = p.left; + return p; + } + + /** + * Returns the last Entry in the TreeMap7 (according to the TreeMap7's + * key-sort function). Returns null if the TreeMap7 is empty. + */ + final Entry getLastEntry() { + Entry p = root; + if (p != null) + while (p.right != null) + p = p.right; + return p; + } + + /** + * Returns the successor of the specified Entry, or null if no such. + */ + static TreeMap7.Entry successor(Entry t) { + if (t == null) + return null; + else if (t.right != null) { + Entry p = t.right; + while (p.left != null) + p = p.left; + return p; + } else { + Entry p = t.parent; + Entry ch = t; + while (p != null && ch == p.right) { + ch = p; + p = p.parent; + } + return p; + } + } + + /** + * Returns the predecessor of the specified Entry, or null if no such. + */ + static Entry predecessor(Entry t) { + if (t == null) + return null; + else if (t.left != null) { + Entry p = t.left; + while (p.right != null) + p = p.right; + return p; + } else { + Entry p = t.parent; + Entry ch = t; + while (p != null && ch == p.left) { + ch = p; + p = p.parent; + } + return p; + } + } + + /** + * Balancing operations. + * + * Implementations of rebalancings during insertion and deletion are + * slightly different than the CLR version. Rather than using dummy + * nilnodes, we use a set of accessors that deal properly with null. They + * are used to avoid messiness surrounding nullness checks in the main + * algorithms. + */ + + private static boolean colorOf(Entry p) { + return (p == null ? BLACK : p.color); + } + + private static Entry parentOf(Entry p) { + return (p == null ? null: p.parent); + } + + private static void setColor(Entry p, boolean c) { + if (p != null) + p.color = c; + } + + private static Entry leftOf(Entry p) { + return (p == null) ? null: p.left; + } + + private static Entry rightOf(Entry p) { + return (p == null) ? null: p.right; + } + + /** From CLR */ + private void rotateLeft(Entry p) { + if (p != null) { + Entry r = p.right; + p.right = r.left; + if (r.left != null) + r.left.parent = p; + r.parent = p.parent; + if (p.parent == null) + root = r; + else if (p.parent.left == p) + p.parent.left = r; + else + p.parent.right = r; + r.left = p; + p.parent = r; + } + } + + /** From CLR */ + private void rotateRight(Entry p) { + if (p != null) { + Entry l = p.left; + p.left = l.right; + if (l.right != null) l.right.parent = p; + l.parent = p.parent; + if (p.parent == null) + root = l; + else if (p.parent.right == p) + p.parent.right = l; + else p.parent.left = l; + l.right = p; + p.parent = l; + } + } + + /** From CLR */ + private void fixAfterInsertion(Entry x) { + x.color = RED; + + while (x != null && x != root && x.parent.color == RED) { + if (parentOf(x) == leftOf(parentOf(parentOf(x)))) { + Entry y = rightOf(parentOf(parentOf(x))); + if (colorOf(y) == RED) { + setColor(parentOf(x), BLACK); + setColor(y, BLACK); + setColor(parentOf(parentOf(x)), RED); + x = parentOf(parentOf(x)); + } else { + if (x == rightOf(parentOf(x))) { + x = parentOf(x); + rotateLeft(x); + } + setColor(parentOf(x), BLACK); + setColor(parentOf(parentOf(x)), RED); + rotateRight(parentOf(parentOf(x))); + } + } else { + Entry y = leftOf(parentOf(parentOf(x))); + if (colorOf(y) == RED) { + setColor(parentOf(x), BLACK); + setColor(y, BLACK); + setColor(parentOf(parentOf(x)), RED); + x = parentOf(parentOf(x)); + } else { + if (x == leftOf(parentOf(x))) { + x = parentOf(x); + rotateRight(x); + } + setColor(parentOf(x), BLACK); + setColor(parentOf(parentOf(x)), RED); + rotateLeft(parentOf(parentOf(x))); + } + } + } + root.color = BLACK; + } + + /** + * Delete node p, and then rebalance the tree. + */ + private void deleteEntry(Entry p) { + modCount++; + size--; + + // If strictly internal, copy successor's element to p and then make p + // point to successor. + if (p.left != null && p.right != null) { + Entry s = successor(p); + p.key = s.key; + p.value = s.value; + p = s; + } // p has 2 children + + // Start fixup at replacement node, if it exists. + Entry replacement = (p.left != null ? p.left : p.right); + + if (replacement != null) { + // Link replacement to parent + replacement.parent = p.parent; + if (p.parent == null) + root = replacement; + else if (p == p.parent.left) + p.parent.left = replacement; + else + p.parent.right = replacement; + + // Null out links so they are OK to use by fixAfterDeletion. + p.left = p.right = p.parent = null; + + // Fix replacement + if (p.color == BLACK) + fixAfterDeletion(replacement); + } else if (p.parent == null) { // return if we are the only node. + root = null; + } else { // No children. Use self as phantom replacement and unlink. + if (p.color == BLACK) + fixAfterDeletion(p); + + if (p.parent != null) { + if (p == p.parent.left) + p.parent.left = null; + else if (p == p.parent.right) + p.parent.right = null; + p.parent = null; + } + } + } + + /** From CLR */ + private void fixAfterDeletion(Entry x) { + while (x != root && colorOf(x) == BLACK) { + if (x == leftOf(parentOf(x))) { + Entry sib = rightOf(parentOf(x)); + + if (colorOf(sib) == RED) { + setColor(sib, BLACK); + setColor(parentOf(x), RED); + rotateLeft(parentOf(x)); + sib = rightOf(parentOf(x)); + } + + if (colorOf(leftOf(sib)) == BLACK && + colorOf(rightOf(sib)) == BLACK) { + setColor(sib, RED); + x = parentOf(x); + } else { + if (colorOf(rightOf(sib)) == BLACK) { + setColor(leftOf(sib), BLACK); + setColor(sib, RED); + rotateRight(sib); + sib = rightOf(parentOf(x)); + } + setColor(sib, colorOf(parentOf(x))); + setColor(parentOf(x), BLACK); + setColor(rightOf(sib), BLACK); + rotateLeft(parentOf(x)); + x = root; + } + } else { // symmetric + Entry sib = leftOf(parentOf(x)); + + if (colorOf(sib) == RED) { + setColor(sib, BLACK); + setColor(parentOf(x), RED); + rotateRight(parentOf(x)); + sib = leftOf(parentOf(x)); + } + + if (colorOf(rightOf(sib)) == BLACK && + colorOf(leftOf(sib)) == BLACK) { + setColor(sib, RED); + x = parentOf(x); + } else { + if (colorOf(leftOf(sib)) == BLACK) { + setColor(rightOf(sib), BLACK); + setColor(sib, RED); + rotateLeft(sib); + sib = leftOf(parentOf(x)); + } + setColor(sib, colorOf(parentOf(x))); + setColor(parentOf(x), BLACK); + setColor(leftOf(sib), BLACK); + rotateRight(parentOf(x)); + x = root; + } + } + } + + setColor(x, BLACK); + } + + private static final long serialVersionUID = 919286545866124006L; + + /** + * Save the state of the {@code TreeMap7} instance to a stream (i.e., + * serialize it). + * + * @serialData The size of the TreeMap7 (the number of key-value + * mappings) is emitted (int), followed by the key (Object) + * and value (Object) for each key-value mapping represented + * by the TreeMap7. The key-value mappings are emitted in + * key-order (as determined by the TreeMap7's Comparator, + * or by the keys' natural ordering if the TreeMap7 has no + * Comparator). + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out the Comparator and any hidden stuff + s.defaultWriteObject(); + + // Write out size (number of Mappings) + s.writeInt(size); + + // Write out keys and values (alternating) + for (Iterator> i = entrySet().iterator(); i.hasNext(); ) { + Map.Entry e = i.next(); + s.writeObject(e.getKey()); + s.writeObject(e.getValue()); + } + } + + /** + * Reconstitute the {@code TreeMap7} instance from a stream (i.e., + * deserialize it). + */ + private void readObject(final java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in the Comparator and any hidden stuff + s.defaultReadObject(); + + // Read in size + int size = s.readInt(); + + buildFromSorted(size, null, s, null); + } + + /** Intended to be called only from TreeSet.readObject */ + void readTreeSet(int size, java.io.ObjectInputStream s, V defaultVal) + throws java.io.IOException, ClassNotFoundException { + buildFromSorted(size, null, s, defaultVal); + } + + /** Intended to be called only from TreeSet.addAll */ + void addAllForTreeSet(SortedSet set, V defaultVal) { + try { + buildFromSorted(set.size(), set.iterator(), null, defaultVal); + } catch (java.io.IOException cannotHappen) { + } catch (ClassNotFoundException cannotHappen) { + } + } + + + /** + * Linear time tree building algorithm from sorted data. Can accept keys + * and/or values from iterator or stream. This leads to too many + * parameters, but seems better than alternatives. The four formats + * that this method accepts are: + * + * 1) An iterator of Map.Entries. (it != null, defaultVal == null). + * 2) An iterator of keys. (it != null, defaultVal != null). + * 3) A stream of alternating serialized keys and values. + * (it == null, defaultVal == null). + * 4) A stream of serialized keys. (it == null, defaultVal != null). + * + * It is assumed that the comparator of the TreeMap7 is already set prior + * to calling this method. + * + * @param size the number of keys (or key-value pairs) to be read from + * the iterator or stream + * @param it If non-null, new entries are created from entries + * or keys read from this iterator. + * @param str If non-null, new entries are created from keys and + * possibly values read from this stream in serialized form. + * Exactly one of it and str should be non-null. + * @param defaultVal if non-null, this default value is used for + * each value in the map. If null, each value is read from + * iterator or stream, as described above. + * @throws IOException propagated from stream reads. This cannot + * occur if str is null. + * @throws ClassNotFoundException propagated from readObject. + * This cannot occur if str is null. + */ + private void buildFromSorted(int size, Iterator it, + java.io.ObjectInputStream str, + V defaultVal) + throws java.io.IOException, ClassNotFoundException { + this.size = size; + root = buildFromSorted(0, 0, size-1, computeRedLevel(size), + it, str, defaultVal); + } + + /** + * Recursive "helper method" that does the real work of the + * previous method. Identically named parameters have + * identical definitions. Additional parameters are documented below. + * It is assumed that the comparator and size fields of the TreeMap7 are + * already set prior to calling this method. (It ignores both fields.) + * + * @param level the current level of tree. Initial call should be 0. + * @param lo the first element index of this subtree. Initial should be 0. + * @param hi the last element index of this subtree. Initial should be + * size-1. + * @param redLevel the level at which nodes should be red. + * Must be equal to computeRedLevel for tree of this size. + */ + private final Entry buildFromSorted(int level, int lo, int hi, + int redLevel, + Iterator it, + java.io.ObjectInputStream str, + V defaultVal) + throws java.io.IOException, ClassNotFoundException { + /* + * Strategy: The root is the middlemost element. To get to it, we + * have to first recursively construct the entire left subtree, + * so as to grab all of its elements. We can then proceed with right + * subtree. + * + * The lo and hi arguments are the minimum and maximum + * indices to pull out of the iterator or stream for current subtree. + * They are not actually indexed, we just proceed sequentially, + * ensuring that items are extracted in corresponding order. + */ + + if (hi < lo) return null; + + int mid = (lo + hi) >>> 1; + + Entry left = null; + if (lo < mid) + left = buildFromSorted(level+1, lo, mid - 1, redLevel, + it, str, defaultVal); + + // extract key and/or value from iterator or stream + K key; + V value; + if (it != null) { + if (defaultVal==null) { + Map.Entry entry = (Map.Entry)it.next(); + key = entry.getKey(); + value = entry.getValue(); + } else { + key = (K)it.next(); + value = defaultVal; + } + } else { // use stream + key = (K) str.readObject(); + value = (defaultVal != null ? defaultVal : (V) str.readObject()); + } + + Entry middle = new Entry(key, value, null); + + // color nodes in non-full bottommost level red + if (level == redLevel) + middle.color = RED; + + if (left != null) { + middle.left = left; + left.parent = middle; + } + + if (mid < hi) { + Entry right = buildFromSorted(level+1, mid+1, hi, redLevel, + it, str, defaultVal); + middle.right = right; + right.parent = middle; + } + + return middle; + } + + /** + * Find the level down to which to assign all nodes BLACK. This is the + * last `full' level of the complete binary tree produced by + * buildTree. The remaining nodes are colored RED. (This makes a `nice' + * set of color assignments wrt future insertions.) This level number is + * computed by finding the number of splits needed to reach the zeroeth + * node. (The answer is ~lg(N), but in any case must be computed by same + * quick O(lg(N)) loop.) + */ + private static int computeRedLevel(int sz) { + int level = 0; + for (int m = sz - 1; m >= 0; m = m / 2 - 1) + level++; + return level; + } +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/util/java7_util/TreeSet7.java b/src/ooxml/java/org/apache/poi/util/java7_util/TreeSet7.java new file mode 100644 index 000000000..3369b9c1f --- /dev/null +++ b/src/ooxml/java/org/apache/poi/util/java7_util/TreeSet7.java @@ -0,0 +1,554 @@ +/* + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.apache.poi.util.java7_util; + +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.ConcurrentModificationException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeMap; + +/** + * A {@link NavigableSet7} implementation based on a {@link TreeMap}. + * The elements are ordered using their {@linkplain Comparable natural + * ordering}, or by a {@link Comparator} provided at set creation + * time, depending on which constructor is used. + * + *

This implementation provides guaranteed log(n) time cost for the basic + * operations ({@code add}, {@code remove} and {@code contains}). + * + *

Note that the ordering maintained by a set (whether or not an explicit + * comparator is provided) must be consistent with equals if it is to + * correctly implement the {@code Set} interface. (See {@code Comparable} + * or {@code Comparator} for a precise definition of consistent with + * equals.) This is so because the {@code Set} interface is defined in + * terms of the {@code equals} operation, but a {@code TreeSet7} instance + * performs all element comparisons using its {@code compareTo} (or + * {@code compare}) method, so two elements that are deemed equal by this method + * are, from the standpoint of the set, equal. The behavior of a set + * is well-defined even if its ordering is inconsistent with equals; it + * just fails to obey the general contract of the {@code Set} interface. + * + *

Note that this implementation is not synchronized. + * If multiple threads access a tree set concurrently, and at least one + * of the threads modifies the set, it must be synchronized + * externally. This is typically accomplished by synchronizing on some + * object that naturally encapsulates the set. + * If no such object exists, the set should be "wrapped" using the + * {@link Collections#synchronizedSortedSet Collections.synchronizedSortedSet} + * method. This is best done at creation time, to prevent accidental + * unsynchronized access to the set:

+ *   SortedSet s = Collections.synchronizedSortedSet(new TreeSet7(...));
+ * + *

The iterators returned by this class's {@code iterator} method are + * fail-fast: if the set is modified at any time after the iterator is + * created, in any way except through the iterator's own {@code remove} + * method, the iterator will throw a {@link ConcurrentModificationException}. + * Thus, in the face of concurrent modification, the iterator fails quickly + * and cleanly, rather than risking arbitrary, non-deterministic behavior at + * an undetermined time in the future. + * + *

Note that the fail-fast behavior of an iterator cannot be guaranteed + * as it is, generally speaking, impossible to make any hard guarantees in the + * presence of unsynchronized concurrent modification. Fail-fast iterators + * throw {@code ConcurrentModificationException} on a best-effort basis. + * Therefore, it would be wrong to write a program that depended on this + * exception for its correctness: the fail-fast behavior of iterators + * should be used only to detect bugs. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @param the type of elements maintained by this set + * + * @author Josh Bloch + * @see Collection + * @see Set + * @see HashSet + * @see Comparable + * @see Comparator + * @see TreeMap + * @since 1.2 + */ + +public class TreeSet7 extends AbstractSet7 + implements NavigableSet7, Cloneable, java.io.Serializable +{ + /** + * The backing map. + */ + private transient NavigableMap7 m; + + // Dummy value to associate with an Object in the backing Map + private static final Object PRESENT = new Object(); + + /** + * Constructs a set backed by the specified navigable map. + */ + TreeSet7(NavigableMap7 m) { + this.m = m; + } + + /** + * Constructs a new, empty tree set, sorted according to the + * natural ordering of its elements. All elements inserted into + * the set must implement the {@link Comparable} interface. + * Furthermore, all such elements must be mutually + * comparable: {@code e1.compareTo(e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the set. If the user attempts to add an element + * to the set that violates this constraint (for example, the user + * attempts to add a string element to a set whose elements are + * integers), the {@code add} call will throw a + * {@code ClassCastException}. + */ + public TreeSet7() { + this(new TreeMap7()); + } + + /** + * Constructs a new, empty tree set, sorted according to the specified + * comparator. All elements inserted into the set must be mutually + * comparable by the specified comparator: {@code comparator.compare(e1, + * e2)} must not throw a {@code ClassCastException} for any elements + * {@code e1} and {@code e2} in the set. If the user attempts to add + * an element to the set that violates this constraint, the + * {@code add} call will throw a {@code ClassCastException}. + * + * @param comparator the comparator that will be used to order this set. + * If {@code null}, the {@linkplain Comparable natural + * ordering} of the elements will be used. + */ + public TreeSet7(Comparator comparator) { + this(new TreeMap7(comparator)); + } + + /** + * Constructs a new tree set containing the elements in the specified + * collection, sorted according to the natural ordering of its + * elements. All elements inserted into the set must implement the + * {@link Comparable} interface. Furthermore, all such elements must be + * mutually comparable: {@code e1.compareTo(e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the set. + * + * @param c collection whose elements will comprise the new set + * @throws ClassCastException if the elements in {@code c} are + * not {@link Comparable}, or are not mutually comparable + * @throws NullPointerException if the specified collection is null + */ + public TreeSet7(Collection c) { + this(); + addAll(c); + } + + /** + * Constructs a new tree set containing the same elements and + * using the same ordering as the specified sorted set. + * + * @param s sorted set whose elements will comprise the new set + * @throws NullPointerException if the specified sorted set is null + */ + public TreeSet7(SortedSet s) { + this(s.comparator()); + addAll(s); + } + + /** + * Returns an iterator over the elements in this set in ascending order. + * + * @return an iterator over the elements in this set in ascending order + */ + public Iterator iterator() { + return m.navigableKeySet().iterator(); + } + + /** + * Returns an iterator over the elements in this set in descending order. + * + * @return an iterator over the elements in this set in descending order + * @since 1.6 + */ + public Iterator descendingIterator() { + return m.descendingKeySet().iterator(); + } + + /** + * @since 1.6 + */ + public NavigableSet7 descendingSet() { + return new TreeSet7(m.descendingMap()); + } + + /** + * Returns the number of elements in this set (its cardinality). + * + * @return the number of elements in this set (its cardinality) + */ + public int size() { + return m.size(); + } + + /** + * Returns {@code true} if this set contains no elements. + * + * @return {@code true} if this set contains no elements + */ + public boolean isEmpty() { + return m.isEmpty(); + } + + /** + * Returns {@code true} if this set contains the specified element. + * More formally, returns {@code true} if and only if this set + * contains an element {@code e} such that + * (o==null ? e==null : o.equals(e)). + * + * @param o object to be checked for containment in this set + * @return {@code true} if this set contains the specified element + * @throws ClassCastException if the specified object cannot be compared + * with the elements currently in the set + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + */ + public boolean contains(Object o) { + return m.containsKey(o); + } + + /** + * Adds the specified element to this set if it is not already present. + * More formally, adds the specified element {@code e} to this set if + * the set contains no element {@code e2} such that + * (e==null ? e2==null : e.equals(e2)). + * If this set already contains the element, the call leaves the set + * unchanged and returns {@code false}. + * + * @param e element to be added to this set + * @return {@code true} if this set did not already contain the specified + * element + * @throws ClassCastException if the specified object cannot be compared + * with the elements currently in this set + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + */ + public boolean add(E e) { + return m.put(e, PRESENT)==null; + } + + /** + * Removes the specified element from this set if it is present. + * More formally, removes an element {@code e} such that + * (o==null ? e==null : o.equals(e)), + * if this set contains such an element. Returns {@code true} if + * this set contained the element (or equivalently, if this set + * changed as a result of the call). (This set will not contain the + * element once the call returns.) + * + * @param o object to be removed from this set, if present + * @return {@code true} if this set contained the specified element + * @throws ClassCastException if the specified object cannot be compared + * with the elements currently in this set + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + */ + public boolean remove(Object o) { + return m.remove(o)==PRESENT; + } + + /** + * Removes all of the elements from this set. + * The set will be empty after this call returns. + */ + public void clear() { + m.clear(); + } + + /** + * Adds all of the elements in the specified collection to this set. + * + * @param c collection containing elements to be added to this set + * @return {@code true} if this set changed as a result of the call + * @throws ClassCastException if the elements provided cannot be compared + * with the elements currently in the set + * @throws NullPointerException if the specified collection is null or + * if any element is null and this set uses natural ordering, or + * its comparator does not permit null elements + */ + public boolean addAll(Collection c) { + // Use linear-time version if applicable + if (m.size()==0 && c.size() > 0 && + c instanceof SortedSet && + m instanceof TreeMap7) { + SortedSet set = (SortedSet) c; + TreeMap7 map = (TreeMap7) m; + @SuppressWarnings("unchecked") + Comparator cc = (Comparator) set.comparator(); + Comparator mc = map.comparator(); + if (cc==mc || (cc != null && cc.equals(mc))) { + map.addAllForTreeSet(set, PRESENT); + return true; + } + } + return super.addAll(c); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} or {@code toElement} + * is null and this set uses natural ordering, or its comparator + * does not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + public NavigableSet7 subSet(E fromElement, boolean fromInclusive, + E toElement, boolean toInclusive) { + return new TreeSet7(m.subMap(fromElement, fromInclusive, + toElement, toInclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toElement} is null and + * this set uses natural ordering, or its comparator does + * not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + public NavigableSet7 headSet(E toElement, boolean inclusive) { + return new TreeSet7(m.headMap(toElement, inclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} is null and + * this set uses natural ordering, or its comparator does + * not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + * @since 1.6 + */ + public NavigableSet7 tailSet(E fromElement, boolean inclusive) { + return new TreeSet7(m.tailMap(fromElement, inclusive)); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} or + * {@code toElement} is null and this set uses natural ordering, + * or its comparator does not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + */ + public SortedSet subSet(E fromElement, E toElement) { + return subSet(fromElement, true, toElement, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code toElement} is null + * and this set uses natural ordering, or its comparator does + * not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + */ + public SortedSet headSet(E toElement) { + return headSet(toElement, false); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if {@code fromElement} is null + * and this set uses natural ordering, or its comparator does + * not permit null elements + * @throws IllegalArgumentException {@inheritDoc} + */ + public SortedSet tailSet(E fromElement) { + return tailSet(fromElement, true); + } + + public Comparator comparator() { + return m.comparator(); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E first() { + return m.firstKey(); + } + + /** + * @throws NoSuchElementException {@inheritDoc} + */ + public E last() { + return m.lastKey(); + } + + // NavigableSet API methods + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + * @since 1.6 + */ + public E lower(E e) { + return m.lowerKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + * @since 1.6 + */ + public E floor(E e) { + return m.floorKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + * @since 1.6 + */ + public E ceiling(E e) { + return m.ceilingKey(e); + } + + /** + * @throws ClassCastException {@inheritDoc} + * @throws NullPointerException if the specified element is null + * and this set uses natural ordering, or its comparator + * does not permit null elements + * @since 1.6 + */ + public E higher(E e) { + return m.higherKey(e); + } + + /** + * @since 1.6 + */ + public E pollFirst() { + Map.Entry e = m.pollFirstEntry(); + return (e == null) ? null : e.getKey(); + } + + /** + * @since 1.6 + */ + public E pollLast() { + Map.Entry e = m.pollLastEntry(); + return (e == null) ? null : e.getKey(); + } + + /** + * Returns a shallow copy of this {@code TreeSet7} instance. (The elements + * themselves are not cloned.) + * + * @return a shallow copy of this set + */ + @SuppressWarnings("unchecked") + public Object clone() { + TreeSet7 clone = null; + try { + clone = (TreeSet7) super.clone(); + } catch (CloneNotSupportedException e) { + throw new InternalError(); + } + + clone.m = new TreeMap7(m); + return clone; + } + + /** + * Save the state of the {@code TreeSet7} instance to a stream (that is, + * serialize it). + * + * @serialData Emits the comparator used to order this set, or + * {@code null} if it obeys its elements' natural ordering + * (Object), followed by the size of the set (the number of + * elements it contains) (int), followed by all of its + * elements (each an Object) in order (as determined by the + * set's Comparator, or by the elements' natural ordering if + * the set has no Comparator). + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out any hidden stuff + s.defaultWriteObject(); + + // Write out Comparator + s.writeObject(m.comparator()); + + // Write out size + s.writeInt(m.size()); + + // Write out all elements in the proper order. + for (E e : m.keySet()) + s.writeObject(e); + } + + /** + * Reconstitute the {@code TreeSet7} instance from a stream (that is, + * deserialize it). + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in any hidden stuff + s.defaultReadObject(); + + // Read in Comparator + @SuppressWarnings("unchecked") + Comparator c = (Comparator) s.readObject(); + + // Create backing TreeMap + TreeMap7 tm; + if (c==null) + tm = new TreeMap7(); + else + tm = new TreeMap7(c); + m = tm; + + // Read in size + int size = s.readInt(); + + tm.readTreeSet(size, s, PRESENT); + } + + private static final long serialVersionUID = -2479143000061671589L; +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java index e8751ef89..4b2bdc423 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java @@ -25,9 +25,9 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Set; -import java.util.TreeSet; import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.util.java7_util.TreeSet7; import org.apache.poi.xssf.util.CTColComparator; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols; @@ -95,7 +95,7 @@ public class ColumnHelper { */ private void sweepCleanColumns(CTCols cols, CTCol[] flattenedColsArray, CTCol overrideColumn) { List flattenedCols = new ArrayList(Arrays.asList(flattenedColsArray)); - TreeSet currentElements = new TreeSet(new CTColByMaxComparator()); + TreeSet7 currentElements = new TreeSet7(new CTColByMaxComparator()); ListIterator flIter = flattenedCols.listIterator(); CTCol haveOverrideColumn = null; long lastMaxIndex = 0;